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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
isNotEmpty = complement(either(isNil, isEmpty))
Example #17
Source File: index.ts    From dts-loader with MIT License 5 votes vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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 vote down vote up
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>
  );
}