ramda#isEmpty TypeScript Examples
The following examples show how to use
ramda#isEmpty.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts From reskript with MIT License | 7 votes |
drawFeatureMatrix = (projectSettings: ProjectSettings, only?: string): void => {
const buildTargets = only
? [only]
: difference(Object.keys(projectSettings.featureMatrix), projectSettings.build.excludeFeatures);
const headers: Column[] = [
{value: '', align: 'left'},
...buildTargets.map(target => ({value: target})),
];
const featureNames = Object.keys(Object.values(projectSettings.featureMatrix)[0]);
if (isEmpty(featureNames)) {
return;
}
const nameToValues = (name: string): string[] => [
name,
...buildTargets.map(target => projectSettings.featureMatrix[target][name]).map(printableValue),
];
const rows = featureNames.map(nameToValues);
const table = new ConsoleTable(headers, rows);
logger.log(table.render());
}
Example #2
Source File: User.tsx From react-js-tutorial with MIT License | 6 votes |
render() {
const { username } = this.props;
return isEmpty(username) ? (
<h3>
Nice to see you! Lets <Link to="/login">login</Link> to the game!
</h3>
) : (
<div>
<h3>Hello, {username}!</h3>
<button onClick={this.logout}>Logout</button>
</div>
);
}
Example #3
Source File: Courses.tsx From react-js-tutorial with MIT License | 6 votes |
onSubmit = async (event: FormEvent) => {
event.preventDefault();
const { search } = this.state;
if (!isEmpty(search)) {
const { courses } = await sendRequest(search);
this.setState({ courses });
}
};
Example #4
Source File: Chat.tsx From react-js-tutorial with MIT License | 6 votes |
onSubmit = (event: FormEvent): void => {
event.preventDefault();
const { message } = this.state;
const { username, send } = this.props;
if (!isEmpty(message)) {
send({ message, author: username });
this.setState({ message: "" });
}
};
Example #5
Source File: Chat.tsx From react-js-tutorial with MIT License | 6 votes |
render(): ReactNode {
const { message } = this.state;
const { username, chat } = this.props;
return !isEmpty(username) ? (
<>
{chat.map(({ author, message }, idx) => (
<MessageComponent key={`${author}_${message}_${idx}`} author={author}>
{message}
</MessageComponent>
))}
<form onSubmit={this.onSubmit} role="form">
<label>
Message:
<input
placeholder="Enter your msg"
value={message}
onChange={this.onChange}
required
minLength={4}
maxLength={10}
/>
</label>
<button>Send</button>
</form>
</>
) : null;
}
Example #6
Source File: Login.tsx From react-js-tutorial with MIT License | 6 votes |
LoginComponent: React.FC<Props> = ({ username, login }) => {
const [name, setName] = useState(username);
const onSubmit = useCallback(
async (ev) => {
ev.preventDefault();
if (!isEmpty(name)) {
login(name);
}
},
[name, login]
);
return isEmpty(username) ? (
<form role="form" onSubmit={onSubmit}>
<label>
Name:
<input
type="text"
placeholder="Enter your login"
value={name}
onChange={(ev) => setName((ev.target as HTMLInputElement).value)}
required
minLength={4}
maxLength={10}
/>
</label>
<button>Login</button>
</form>
) : (
<Redirect to="/ticktacktoe" />
);
}
Example #7
Source File: qr.ts From back-home-safe with GNU General Public License v3.0 | 6 votes |
qrEncode = ({
typeEn,
typeZh,
nameEn,
nameZh,
type,
venueCode,
venueID,
}: EncodeParam) => {
const json = {
metadata: !isEmpty(typeEn) || !isEmpty(typeZh) ? { typeEn, typeZh } : null,
nameZh,
nameEn,
type,
hash: getHash(venueID),
};
const base64Data = window.btoa(
unescape(encodeURIComponent(JSON.stringify(json)))
);
return `HKEN:${venueCode}${venueID}${base64Data}`;
}
Example #8
Source File: qr.ts From back-home-safe with GNU General Public License v3.0 | 6 votes |
getVenueName = (
decodedJson: DecodedJSON | Location | null,
language: languageType
) => {
if (!decodedJson) return "";
const trimmedZhName = trim(propOr("", "nameZh", decodedJson));
const trimmedEnName = trim(propOr("", "nameEn", decodedJson));
const venueId = trim(propOr("", "venueId", decodedJson));
const chineseName = !isEmpty(trimmedZhName)
? trimmedZhName
: !isEmpty(trimmedEnName)
? trimmedEnName
: // used for taxi license
venueId;
const englishName = !isEmpty(trimmedEnName)
? trimmedEnName
: !isEmpty(trimmedZhName)
? trimmedZhName
: // used for taxi license
venueId;
return language === languageType.EN ? englishName : chineseName;
}
Example #9
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 6 votes |
VaccinationQRReader = () => {
const { t } = useTranslation("vaccination_qr_reader");
const [result, setResult] = useState<DecodedJSON | null>(null);
const handleScan = async ({ data }: QRCode) => {
if (!data || isEmpty(data)) return;
const decodedJson = await qrDecode(data);
if (!decodedJson) return;
console.log(data, decodedJson);
setResult(decodedJson);
};
return (
<PageWrapper>
<Header backPath="/" name={t("name")} />
<Message>{t("message.scan_qr_code")}</Message>
<VideoContainer>
{result && (
<ResultOverlay>
<ReactJson src={result} />
</ResultOverlay>
)}
<Overlay />
<QRCodeReader onDecode={handleScan} />
</VideoContainer>
</PageWrapper>
);
}
Example #10
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 6 votes |
stepsSettings = ({
t,
password,
setPassword,
}: {
t: TFunction;
password: string;
setPassword: (value: string) => void;
}) => [
{
key: steps.LANGUAGE,
name: t("language.name"),
nextButtonText: t("global:button.next_page"),
component: <Language />,
},
{
key: steps.ADD_TO_HOME_SCREEN,
name: t("add_to_home_screen.name"),
nextButtonText: t("global:button.complete"),
component: <AddToHomeScreen />,
},
{
key: steps.DISCLAIMER,
name: t("disclaimer.name"),
nextButtonText: t("disclaimer.accept"),
component: <Disclaimer />,
},
{
key: steps.SET_UP_PASSWORD,
name: t("setup_password.name"),
nextButtonText: !isEmpty(password)
? t("global:button.set")
: t("global:button.skip"),
component: <SetupPassword value={password} onChange={setPassword} />,
},
]
Example #11
Source File: saga.ts From react-js-tutorial with MIT License | 6 votes |
export function* checkUserSession() {
const userSession: string = yield call(getUserSession);
if (userSession?.length > usernameMinLength && !isEmpty(userSession)) {
yield put(actions.login(userSession));
} else {
yield put(actions.logout());
yield* clearUserSession();
}
}
Example #12
Source File: overrides.ts From the-fake-backend with ISC License | 6 votes |
applyExternalOverrides() {
if (!this.fileStorage?.options.enabled || !this.fileStorage.isInitialized())
return;
if (this.fileStorage.isEmpty()) {
this.fileStorage?.setItem(FILE_STORAGE_KEY, this.getAllSelected());
} else {
const persistedOverrides = this.fileStorage.getItem<Override[]>(
FILE_STORAGE_KEY
);
persistedOverrides?.forEach((override) => {
const overridableRoutes = this.getAll();
const url = override.routePath;
const route = findRouteByUrl(overridableRoutes, url);
const type = override.methodType;
const overrides = getMethodOverridesByType(route, type.toLowerCase());
const name = override.name;
overrides.forEach((override) => {
override.selected = override.name === name;
});
});
}
}
Example #13
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 6 votes |
CameraSetting = () => {
const { t } = useTranslation("camera_setting");
const { preferredCameraId, setPreferredCameraId, cameraList } = useCamera();
return (
<PageWrapper>
<Header backPath="/" name={t("name")} />
<FormWrapper>
<StyledFormControl>
<InputLabel id="cameraId">{t("form.camera_choice.label")}</InputLabel>
<Select
labelId="cameraId"
id="demo-simple-select"
value={preferredCameraId}
onChange={(e) => {
setPreferredCameraId((e.target.value as string) || "AUTO");
}}
>
<MenuItem value="AUTO">{t("form.camera_choice.auto")}</MenuItem>
{cameraList.map(({ deviceId, label }) => (
<MenuItem value={deviceId} key="deviceId">
{isNil(label) || isEmpty(label) ? deviceId : label}
</MenuItem>
))}
</Select>
<FormHelperText>{t("form.camera_choice.explain")}</FormHelperText>
</StyledFormControl>
</FormWrapper>
<VideoContainer>
<MediaStream suppressError />
</VideoContainer>
</PageWrapper>
);
}
Example #14
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
Login = () => {
const { t } = useTranslation("login");
const [password, setPassword] = useState("");
const { unlockStore } = useData();
const [showPasswordError, setShowPasswordError] = useState(false);
const handleLogin = () => {
const success = unlockStore(password);
if (!success) {
setShowPasswordError(true);
setPassword("");
}
};
return (
<PageWrapper>
<Wrapper>
<Unlock />
<div>{t("message.please_input_password")}</div>
<InputWrapper
onSubmit={(e) => {
e.preventDefault();
handleLogin();
}}
>
<TextField
type="password"
autoComplete="current-password"
value={password}
onChange={(e) => {
setPassword(e.target.value);
}}
/>
<ButtonWrapper>
<Button
variant="contained"
color="secondary"
disabled={isEmpty(password)}
type="submit"
>
{t("global:button.unlock")}
</Button>
</ButtonWrapper>
</InputWrapper>
<Button onClick={clearAllData}>{t("button.reset")}</Button>
</Wrapper>
<Snackbar
open={showPasswordError}
autoHideDuration={2000}
onClose={() => {
setShowPasswordError(false);
}}
anchorOrigin={{ vertical: "top", horizontal: "center" }}
>
<Alert elevation={6} variant="filled" severity="error">
{t("message.wrong_password")}
</Alert>
</Snackbar>
</PageWrapper>
);
}
Example #15
Source File: saga.ts From react-js-tutorial with MIT License | 5 votes |
export function* saveUserSession({
payload,
}: ReturnType<typeof actions.login>) {
const username = String(payload);
if (username?.length > usernameMinLength && !isEmpty(username)) {
yield call(login, username);
}
}
Example #16
Source File: overrides.ts From the-fake-backend with ISC License | 5 votes |
isNotEmpty = complement(either(isNil, isEmpty))
Example #17
Source File: index.ts From dts-loader with MIT License | 5 votes |
function emitFile(
context: LoaderContext<Partial<LoaderOptions>>,
languageService: ts.LanguageService,
loaderOptions: LoaderOptions,
) {
const fileName = context.resourcePath
try {
const output = languageService.getEmitOutput(fileName)
if (!output.emitSkipped) {
output.outputFiles.forEach((o) => {
if (o.name.endsWith('.d.ts')) {
fs.ensureDirSync(path.dirname(o.name))
fs.writeFileSync(o.name, o.text)
if (
loaderOptions.exposes &&
!isEmpty(loaderOptions.exposes) &&
!isEmpty(loaderOptions.name)
) {
for (const [key, value] of Object.entries(loaderOptions.exposes)) {
if (key && value) {
context.resolve(context.rootContext, value, (err, inputFilePath) => {
if (err) {
console.error(err)
return
}
if (inputFilePath === fileName) {
const moduleFilename = `${key}.d.ts`
const modulePath = path.resolve(
context.rootContext,
`${loaderOptions.typesOutputDir}/${loaderOptions.name}`
)
const dtsEntryPath = path.resolve(modulePath, moduleFilename)
const relativePathToOutput = normalizePath(
path.relative(
path.dirname(dtsEntryPath),
o.name.replace('.d.ts', '')
)
)
fs.ensureFileSync(dtsEntryPath)
fs.writeFileSync(
dtsEntryPath,
`export * from './${relativePathToOutput}';\nexport { default } from './${relativePathToOutput}';`
)
}
})
}
}
}
}
})
}
} catch (e) {
console.log(`Skip ${fileName}`)
}
}
Example #18
Source File: Courses.tsx From react-js-tutorial with MIT License | 5 votes |
render() {
const { courses, search } = this.state;
return (
<>
<form onSubmit={this.onSubmit}>
<label>
Search:
<input
placeholder="Search..."
value={search}
onChange={this.onChange}
required
minLength={0}
maxLength={10}
/>
</label>
<button>Send</button>
</form>
{!isEmpty(courses)
? courses.map(
({ id, title, topic, author, description, url }: Course) => (
<div key={id}>
<b>
Id: {id}, URL: {url}
</b>
<h4>Title: {title}</h4>
<b>Topic: </b>
<div>{topic}</div>
<b>Author: </b>
<div>{author}</div>
<b>Description: </b>
<div>{description}</div>
</div>
)
)
: null}
</>
);
}
Example #19
Source File: Chat.tsx From react-js-tutorial with MIT License | 5 votes |
onChange = (event: ChangeEvent<HTMLInputElement>): void => {
event.preventDefault();
const message = event.target.value;
if (!isEmpty(message)) {
this.setState({ message });
}
};
Example #20
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
Tutorial = ({
setFinishedTutorial,
}: {
setFinishedTutorial: (value: boolean) => void;
}) => {
const { t } = useTranslation("tutorial");
const { initPassword } = useData();
const [activeStep, setActiveStep] = useState(0);
const [password, setPassword] = useState("");
const {
activeStepComponent: { component, nextButtonText },
isLastStep,
allStep,
} = useMemo(() => {
const allStep = stepsSettings({ password, setPassword, t });
return {
allStep,
activeStepComponent: allStep[activeStep] || {},
isLastStep: activeStep === allStep.length - 1,
};
}, [activeStep, password, setPassword, t]);
const handleNext = () => {
if (isLastStep) {
!isEmpty(password) && initPassword(password);
setFinishedTutorial(true);
} else {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
}
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
return (
<PageWrapper>
<Stepper activeStep={activeStep} alternativeLabel>
{allStep.map(({ key, name }) => (
<Step key={key}>
<StepLabel>{name}</StepLabel>
</Step>
))}
</Stepper>
<ContentWrapper>{component}</ContentWrapper>
<ButtonGroup>
<Button disabled={activeStep === 0} onClick={handleBack}>
{t("global:button.last_page")}
</Button>
<Button variant="contained" color="secondary" onClick={handleNext}>
{nextButtonText
? nextButtonText
: isLastStep
? t("global:button.complete")
: t("global:button.next_page")}
</Button>
</ButtonGroup>
</PageWrapper>
);
}
Example #21
Source File: index.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
QRReader = () => {
const { t } = useTranslation("qr_reader");
const [qrResult, setQrResult] = useState<string | null>(null);
const browserHistory = useHistory();
const { createTravelRecord } = useTravelRecord();
const { language } = useI18n();
const handleScan = ({ data }: QRCode) => {
if (!data || isEmpty(data)) return;
const decodedJson = qrDecode(data);
if (!decodedJson) return;
setQrResult(data);
};
useEffect(() => {
if (!qrResult) return;
const decodedJson = qrDecode(qrResult);
if (!decodedJson || !getVenueName(decodedJson, language)) return;
const trimmedZhName = trim(propOr("", "nameZh", decodedJson));
const trimmedEnName = trim(propOr("", "nameEn", decodedJson));
const id = uuid();
const now = dayjs();
const record = {
id: uuid(),
venueId: decodedJson.venueId,
nameZh: trimmedZhName,
nameEn: trimmedEnName,
type: locationType.PLACE,
inputType: travelRecordInputType.SCAN,
inTime: now.toISOString(),
outTime: now.add(4, "hour").toISOString(),
originalData: decodedJson,
};
createTravelRecord(record);
browserHistory.push({ pathname: `/confirm/${id}`, state: record });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [qrResult, browserHistory]);
return (
<PageWrapper>
<Header backPath="/" name={t("name")} />
<Message>{t("message.scan_qr_code")}</Message>
<VideoContainer>
<Overlay />
<QRCodeReader onDecode={handleScan} />
</VideoContainer>
</PageWrapper>
);
}
Example #22
Source File: QRPreview.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
QRPreview = ({ data, onLeave }: Props) => {
const imgRef = useRef<HTMLImageElement>(null);
useEffect(() => {
if (!imgRef.current) return;
const encodedString = qrEncode(data);
new QrCodeWithLogo({
image: imgRef.current,
content: encodedString,
width: 380,
logo: {
src: data.customImg || baseIcon,
logoRadius: 8,
borderSize: 0,
},
}).toImage();
}, [data]);
return data ? (
<PageWrapper>
<Header>
<Cross src={cross} onClick={onLeave} />
</Header>
<MessageWrapper>
<PlaceWrapper>
{data.nameEn && !isEmpty(data.nameZh) && (
<StyledPlace value={data.nameZh || ""} readOnly />
)}
{data.nameEn && !isEmpty(data.nameEn) && (
<StyledPlace value={data.nameEn || ""} readOnly />
)}
</PlaceWrapper>
</MessageWrapper>
<TickWrapper>
<TickWrapperInner>
<StyledQrCode ref={imgRef} alt="qrCode" />
</TickWrapperInner>
</TickWrapper>
<Address>
{data.addressZh && !isEmpty(data.addressZh) && (
<div>{data.addressZh}</div>
)}
{data.addressEn && !isEmpty(data.addressEn) && (
<div>{data.addressEn}</div>
)}
</Address>
</PageWrapper>
) : (
<></>
);
}
Example #23
Source File: Bookmark.tsx From back-home-safe with GNU General Public License v3.0 | 5 votes |
Bookmark = () => {
const { t } = useTranslation("main_screen");
const { bookmarkLocation, removeBookmarkLocation } = useBookmarkLocation();
const { language } = useI18n();
const { enterLocation } = useTravelRecord();
return (
<PageWrapper>
<Header name={t("bookmark.name")} />
<ContentWrapper>
<List component="nav">
{isEmpty(bookmarkLocation) && (
<Msg>{t("bookmark.message.empty")}</Msg>
)}
{bookmarkLocation.map((item) => {
const name = getVenueName(item, language);
return (
<React.Fragment key={item.id}>
<ListItem dense>
<ListItemIcon>
{item.type === locationType.TAXI ? (
<LocalTaxiIcon />
) : (
<StoreIcon />
)}
</ListItemIcon>
<ListItemText
primary={name}
secondary={dayjs(item.createdAt).format("YYYY-MM-DD HH:mm")}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
aria-label="enter"
onClick={() => {
enterLocation({
...item,
inputType: travelRecordInputType.BOOKMARK,
});
}}
>
<ExitToAppIcon />
</IconButton>
<IconButton
edge="end"
aria-label="delete"
onClick={() => {
removeBookmarkLocation(item.id);
}}
>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
<Divider />
</React.Fragment>
);
})}
</List>
</ContentWrapper>
</PageWrapper>
);
}
Example #24
Source File: processDatabase.ts From kanel with MIT License | 4 votes |
processDatabase = async ({
connection,
preDeleteModelFolder = false,
customTypeMap = {},
modelHooks = [],
modelNominator = nameIdentity,
propertyNominator = (propertyName) =>
propertyName.indexOf(' ') !== -1 ? `'${propertyName}'` : propertyName,
initializerNominator = (modelName) => `${modelName}Initializer`,
idNominator = (modelName) => `${modelName}Id`,
makeIdType = (innerType, modelName) =>
`${innerType} & { " __flavor"?: '${modelName}' };`,
typeHooks = [],
typeNominator = nameIdentity,
fileNominator = identity,
resolveViews = false,
schemas,
...unknownProps
}: Config) => {
if (!isEmpty(unknownProps)) {
logger.warn(
`Unknown configuration properties: ${Object.keys(unknownProps).join(
', '
)}`
);
}
const typeMap = { ...defaultTypeMap, ...customTypeMap };
/** @type {import('./Config').Nominators} */
const nominators = {
modelNominator,
propertyNominator,
initializerNominator,
idNominator,
typeNominator,
fileNominator,
};
const modelProcessChain = [...defaultHooks, ...modelHooks];
const typeProcessChain = [...defaultHooks, ...typeHooks];
if (typeof connection === 'string') {
logger.log(`Connecting to ${chalk.greenBright(connection)}`);
} else {
logger.log(
`Connecting to ${chalk.greenBright(connection.database)} on ${
connection.host
}`
);
}
const schemaFolderMap = map(
(s: SchemaConfig) => path.resolve(s.modelFolder),
indexBy((s) => s.name, schemas)
) as Record<string, string>;
for (const schemaConfig of schemas) {
const schema = await extractSchema(
schemaConfig.name,
connection,
schemaConfig.resolveViews !== undefined
? schemaConfig.resolveViews
: resolveViews
);
if (preDeleteModelFolder) {
logger.log(` - Clearing old files in ${schemaConfig.modelFolder}`);
await rmfr(schemaConfig.modelFolder, { glob: true });
}
if (!fs.existsSync(schemaConfig.modelFolder)) {
fs.mkdirSync(schemaConfig.modelFolder, { recursive: true });
}
await processSchema(
schemaConfig,
schema,
typeMap,
nominators,
modelProcessChain,
typeProcessChain,
schemaFolderMap,
makeIdType
);
}
}
Example #25
Source File: TravelRecord.tsx From back-home-safe with GNU General Public License v3.0 | 4 votes |
TravelRecord = () => {
const { t } = useTranslation("main_screen");
const { pastTravelRecord, removeTravelRecord, autoRemoveRecordDay } =
useTravelRecord();
const { incognito } = useData();
const { language } = useI18n();
const {
createBookmarkLocation,
getBookmarkLocationId,
removeBookmarkLocation,
} = useBookmarkLocation();
return (
<PageWrapper>
<Header name={t("travel_record.name")} />
<ContentWrapper>
<List component="nav">
{incognito && (
<Msg>
<IncognitoIcon src={incognitoIcon} />
{t("travel_record.message.incognito_activated")}
</Msg>
)}
{isEmpty(pastTravelRecord) && (
<Msg>{t("travel_record.message.empty")}</Msg>
)}
{pastTravelRecord.map((item) => {
const name = getVenueName(item, language);
const bookmarkId = getBookmarkLocationId(item);
return (
<React.Fragment key={item.id}>
<ListItemWithWiderSecondaryAction dense button>
<ListItemIcon>
{item.type === locationType.TAXI ? (
<LocalTaxiIcon />
) : (
<StoreIcon />
)}
</ListItemIcon>
<ListItemText
primary={name}
secondary={`${dayjs(item.inTime).format(
"YYYY-MM-DD HH:mm"
)} - ${
item.outTime
? dayjs(item.outTime).format("YYYY-MM-DD HH:mm")
: ""
}`}
/>
<ListItemSecondaryAction>
<IconButton
aria-label="settings"
onClick={() => {
bookmarkId
? removeBookmarkLocation(bookmarkId)
: createBookmarkLocation(item);
}}
>
{bookmarkId ? <BookmarkIcon /> : <BookmarkBorderIcon />}
</IconButton>
<IconButton
edge="end"
aria-label="delete"
onClick={() => {
removeTravelRecord(item.id);
}}
disabled={incognito}
>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItemWithWiderSecondaryAction>
<Divider />
</React.Fragment>
);
})}
</List>
</ContentWrapper>
<AutoRemoveMessage>
{t("travel_record.message.auto_remove_record", {
day: autoRemoveRecordDay,
})}
</AutoRemoveMessage>
</PageWrapper>
);
}
Example #26
Source File: Home.tsx From back-home-safe with GNU General Public License v3.0 | 4 votes |
Home = () => {
const { t } = useTranslation("main_screen");
const [place, setPlace] = useState("");
const [license, setLicense] = useState("");
const [leaveModalOpen, setLeaveModalOpen] = useState(false);
const [leaveId, setLeaveId] = useState<null | string>(null);
const { currentTravelRecord, updateTravelRecord } = useTravelRecord();
const { enterLocation } = useTravelRecord();
const { currentTime } = useTime();
const { language } = useI18n();
const {
createBookmarkLocation,
getBookmarkLocationId,
removeBookmarkLocation,
} = useBookmarkLocation();
const today = useMemo(() => {
return currentTime.format("YYYY-MM-DD, dddd");
}, [currentTime]);
const handlePlaceSubmit = () => {
enterLocation({
nameZh: place,
type: locationType.PLACE,
inputType: travelRecordInputType.MANUALLY,
});
};
const handleTaxiSubmit = () => {
enterLocation({
venueId: license,
type: locationType.TAXI,
inputType: travelRecordInputType.MANUALLY,
});
};
const handleLeave = (date: Dayjs) => {
if (!leaveId) return;
updateTravelRecord(leaveId, {
outTime: date.startOf("minute").toISOString(),
});
setLeaveModalOpen(false);
};
useEffect(() => {
if (leaveId) setLeaveModalOpen(true);
}, [leaveId]);
useEffect(() => {
if (!leaveModalOpen) setLeaveId(null);
}, [leaveModalOpen]);
return (
<PageWrapper>
{leaveId && (
<LeaveModal
id={leaveId}
visible={leaveModalOpen}
onDiscard={() => {
setLeaveModalOpen(false);
}}
onFinish={handleLeave}
/>
)}
<Welcome>
<Title>
<div>{today}</div>
<h2>{t("home.record_your_visit")}</h2>
</Title>
</Welcome>
<SliderWrapper>
<Slider>
<StyledCard>
<CardContent>
<Typography color="textSecondary" gutterBottom>
{t("home.form.venue_name.label")}
</Typography>
<StyledPlace
value={place}
onChange={setPlace}
placeholder={t("home.form.venue_name.placeholder")}
/>
</CardContent>
<CardActions>
<Button
size="small"
color="primary"
disabled={isEmpty(trim(place))}
onClick={handlePlaceSubmit}
>
{t("home.button.go")}
</Button>
<Link to="/qrReader">
<Button size="small" color="primary">
{t("home.button.scan_qr_code")}
</Button>
</Link>
</CardActions>
</StyledCard>
<StyledCard>
<CardContent>
<Typography color="textSecondary" gutterBottom>
{t("home.form.taxi.label")}
</Typography>
<StyledPlace
value={license}
onChange={setLicense}
placeholder={t("home.form.taxi.placeholder")}
/>
</CardContent>
<CardActions>
<Button
size="small"
color="primary"
disabled={isEmpty(trim(license))}
onClick={handleTaxiSubmit}
>
{t("home.button.ride")}
</Button>
</CardActions>
</StyledCard>
</Slider>
</SliderWrapper>
<TravelRecordWrapper>
<TravelRecordInner>
<h3>{t("home.you_have_entered")}</h3>
{isEmpty(currentTravelRecord) && (
<Msg>{t("travel_record.message.empty")}</Msg>
)}
{currentTravelRecord.map((item) => {
const bookmarkId = getBookmarkLocationId(item);
return (
<Item key={item.id}>
<CardHeader
avatar={
item.type === locationType.TAXI ? (
<LocalTaxiIcon />
) : (
<StoreIcon />
)
}
action={
<IconButton
aria-label="settings"
onClick={() => {
bookmarkId
? removeBookmarkLocation(bookmarkId)
: createBookmarkLocation(item);
}}
>
{bookmarkId ? <BookmarkIcon /> : <BookmarkBorderIcon />}
</IconButton>
}
title={getVenueName(item, language)}
subheader={`${dayjs(item.inTime).format(
"YYYY-MM-DD HH:mm"
)} - ${
item.outTime
? dayjs(item.outTime).format("YYYY-MM-DD HH:mm")
: ""
}`}
/>
<CardActions disableSpacing>
<Button
size="small"
color="primary"
onClick={() => {
setLeaveId(item.id);
}}
>
{t("global:button.leave")}
</Button>
<Link to={`/confirm/${item.id}`}>
<Button size="small" color="primary">
{t("global:button.confirm_page")}
</Button>
</Link>
</CardActions>
</Item>
);
})}
</TravelRecordInner>
</TravelRecordWrapper>
</PageWrapper>
);
}