@ant-design/icons#LockOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#LockOutlined. 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: StatusIcon.tsx    From datart with Apache License 2.0 6 votes vote down vote up
LockIcon: React.FC<{
  title: React.ReactNode;
  onClick?: React.MouseEventHandler<HTMLElement> | undefined;
}> = ({ title, onClick }) => {
  return (
    <Tooltip title={title}>
      <Button
        icon={<LockOutlined style={{ color: PRIMARY, opacity: 0.5 }} />}
        type="link"
        onClick={onClick}
      />
    </Tooltip>
  );
}
Example #2
Source File: Login.tsx    From vite-react-ts with MIT License 6 votes vote down vote up
Login: React.FC = () => {
  const { login, loading } = useStore((state) => ({ ...state }));

  return (
    <div className={cls.loginBox}>
      <Card className="_bg" bordered={false}>
        <Form
          onFinish={({ username, password }) => {
            if (username === 'admin' && password === '123456') {
              return login({ username, password });
            }
            message.error('账号或密码错误,请重试!');
          }}>
          <Form.Item
            name="username"
            rules={[{ required: true, message: '请输入用户名' }]}>
            <Input prefix={<UserOutlined />} placeholder="请输入用户名:admin" />
          </Form.Item>
          <Form.Item name="password" rules={[{ required: true, message: '请输入密码' }]}>
            <Input prefix={<LockOutlined />} placeholder="请输入密码:123456" />
          </Form.Item>
          <Form.Item>
            <Button
              loading={loading}
              type="primary"
              htmlType="submit"
              className={cls.button}>
              登陆
            </Button>
          </Form.Item>
        </Form>
      </Card>
    </div>
  );
}
Example #3
Source File: GroupsIntroductionOption.tsx    From posthog-foss with MIT License 6 votes vote down vote up
export function GroupsIntroductionOption({ value }: { value: any }): JSX.Element | null {
    const { groupsAccessStatus } = useValues(groupsAccessLogic)

    if (
        ![GroupsAccessStatus.HasAccess, GroupsAccessStatus.HasGroupTypes, GroupsAccessStatus.NoAccess].includes(
            groupsAccessStatus
        )
    ) {
        return null
    }

    return (
        <Select.Option
            key="groups"
            value={value}
            disabled
            style={{
                height: '100%',
                width: '100%',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
                backgroundColor: 'var(--bg-side)',
                color: 'var(--text-muted)',
            }}
        >
            <LockOutlined style={{ marginRight: 6, color: 'var(--warning)' }} />
            Unique groups –{' '}
            <Link
                to="https://posthog.com/docs/user-guides/group-analytics?utm_medium=in-product&utm_campaign=group-analytics-learn-more"
                target="_blank"
                data-attr="group-analytics-learn-more"
                style={{ fontWeight: 600 }}
            >
                Learn more
            </Link>
        </Select.Option>
    )
}
Example #4
Source File: Login.tsx    From jmix-frontend with Apache License 2.0 5 votes vote down vote up
Login = observer(() => {
  const intl = useIntl();

  const mainStore = useMainStore();

  const [login, setLogin] = useState("");
  const [password, setPassword] = useState("");
  const [performingLoginRequest, setPerformingLoginRequest] = useState(false);

  const changeLogin = useCallback((e: ChangeEvent<HTMLInputElement>) => setLogin(e.target.value), [setLogin]);
  const changePassword = useCallback((e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value), [setPassword]);

  const doLogin = useCallback(() => {
    setPerformingLoginRequest(true);
    mainStore
      .login(login, password)
      .then(action(() => {
        setPerformingLoginRequest(false);
      }))
      .catch(action((error: JmixServerError) => {
        setPerformingLoginRequest(false);

        const loginMessageErrorIntlId = loginMapJmixRestErrorToIntlId(error);
        message.error(intl.formatMessage({id: loginMessageErrorIntlId}));
      }));
  }, [setPerformingLoginRequest, mainStore, intl, login, password]);

  return (
    <Card className={styles.loginForm}>
      <JmixDarkIcon className={styles.logo} />

      <div className={styles.title}>
        <%= title %>
      </div>

      <Form layout='vertical' onFinish={doLogin}>
        <Form.Item>
          <Input id='input_login'
                  placeholder={intl.formatMessage({id: 'login.placeholder.login'})}
                  onChange={changeLogin}
                  value={login}
                  prefix={<UserOutlined style={{ margin: "0 11px 0 0" }}/>}
                  size='large'/>
        </Form.Item>
        <Form.Item>
          <Input id='input_password'
                  placeholder={intl.formatMessage({id: 'login.placeholder.password'})}
                  onChange={changePassword}
                  value={password}
                  type='password'
                  prefix={<LockOutlined style={{ margin: "0 11px 0 0" }}/>}
                  size='large'/>
        </Form.Item>
        <Form.Item>
          <div className={styles.languageSwitcherContainer}>
            <LanguageSwitcher />
          </div>
        </Form.Item>
        <Form.Item>
          <Button type='primary'
                  htmlType='submit'
                  size='large'
                  block={true}
                  loading={performingLoginRequest}>
            <FormattedMessage id='login.loginBtn'/>
          </Button>
        </Form.Item>
      </Form>
    </Card>
  );
})
Example #5
Source File: ChangePasswordOnResetForm.tsx    From jitsu with MIT License 5 votes vote down vote up
ChangePasswordOnResetForm = () => {
  const services = useServices()
  const { resetId } = useParams<{ resetId?: string }>()
  const [isLoading, setIsLoading] = useState<boolean>(false)

  const handleChangePassword = async values => {
    setIsLoading(true)
    try {
      await services.userService.changePassword(values["password"], resetId)
      message.success("Password has been changed!")
      await sleep(800)
      window.location.href = getBaseUIPath() ?? "/"
    } catch (error) {
      handleError(error)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <Card
      title={
        <div className="flex flex-col items-center justify-start">
          <img src={logo} alt="[logo]" className="h-16" />
          <h3 className="pt-6">Set your new password</h3>
        </div>
      }
      style={{ margin: "auto", marginTop: "100px", maxWidth: "500px" }}
      bordered={false}
      className="password-form-card"
    >
      <Form
        name="password-form"
        className="password-form"
        initialValues={{
          remember: false,
        }}
        requiredMark={false}
        layout="vertical"
        onFinish={handleChangePassword}
      >
        <Form.Item
          name="password"
          rules={[
            {
              required: true,
              message: "Please input new Password!",
            },
          ]}
          label={<b>New Password</b>}
        >
          <Input prefix={<LockOutlined />} type="password" placeholder="Password" />
        </Form.Item>

        <div className="password-action-buttons">
          <div>
            <Button type="primary" htmlType="submit" className="login-form-button" loading={isLoading}>
              Save
            </Button>
          </div>
        </div>
      </Form>
    </Card>
  )
}
Example #6
Source File: AccessControl.tsx    From posthog-foss with MIT License 5 votes vote down vote up
export function AccessControl({ isRestricted }: RestrictedComponentProps): JSX.Element {
    const { currentOrganization, currentOrganizationLoading } = useValues(organizationLogic)
    const { currentTeam, currentTeamLoading } = useValues(teamLogic)
    const { updateCurrentTeam } = useActions(teamLogic)
    const { guardAvailableFeature } = useActions(sceneLogic)
    const { hasAvailableFeature } = useValues(userLogic)

    const projectPermissioningEnabled =
        hasAvailableFeature(AvailableFeature.PROJECT_BASED_PERMISSIONING) && currentTeam?.access_control

    return (
        <div>
            <h2 className="subtitle" id="access-control">
                Access Control
            </h2>
            <p>
                {projectPermissioningEnabled ? (
                    <>
                        This project is{' '}
                        <b>
                            <LockOutlined style={{ color: 'var(--warning)', marginRight: 5 }} />
                            private
                        </b>
                        . Only members listed below are allowed to access it.
                    </>
                ) : (
                    <>
                        This project is{' '}
                        <b>
                            <UnlockOutlined style={{ marginRight: 5 }} />
                            open
                        </b>
                        . Any member of the organization can access it. To enable granular access control, make it
                        private.
                    </>
                )}
            </p>
            <Switch
                id="access-control-switch"
                onChange={(checked) => {
                    guardAvailableFeature(
                        AvailableFeature.PROJECT_BASED_PERMISSIONING,
                        'project-based permissioning',
                        'Set permissions granularly for each project. Make sure only the right people have access to protected data.',
                        () => updateCurrentTeam({ access_control: checked })
                    )
                }}
                checked={projectPermissioningEnabled}
                loading={currentOrganizationLoading || currentTeamLoading}
                disabled={isRestricted || !currentOrganization || !currentTeam}
            />
            <label
                style={{
                    marginLeft: '10px',
                }}
                htmlFor="access-control-switch"
            >
                Make project private
            </label>
        </div>
    )
}
Example #7
Source File: Login.tsx    From nodestatus with MIT License 5 votes vote down vote up
Login: FC = () => {
  const navigate = useNavigate();
  const { mutate } = useSWRConfig();

  const onFinish = useCallback(async (values: { username: string, password: string }) => {
    const { username, password } = values;
    const res = await axios.post<IResp<string>>('/api/session', { username, password });
    const { data } = res;
    if (!data.code) {
      notify('Success', undefined, 'success');
      localStorage.setItem('token', data.data);
      mutate('/api/session', { code: 0, msg: 'OK', data: null }, false).then(() => navigate('/dashboard'));
    }
  }, [navigate, mutate]);

  return (
    <div
      className="flex items-center min-h-screen p-6 bg-violet-50"
      style={{ backgroundImage: `url(${loginBackground})` }}
    >
      <div className="flex-1 h-full max-w-xl md:max-w-4xl mx-auto overflow-hidden bg-white rounded-lg shadow-xl">
        <div className="flex flex-col md:flex-row">
          <div className="h-60 md:h-auto md:w-1/2">
            <img
              aria-hidden="true"
              className="object-cover w-full h-full"
              src={cherry}
              alt="Office"
            />
          </div>
          <div className="flex flex-col items-center justify-center p-6 sm:p-16 md:w-1/2">
            <h1 className="text-2xl font-semibold text-gray-700 mb-6">NodeStatus</h1>
            <Form
              className="w-full"
              initialValues={{ remember: true }}
              onFinish={onFinish}
            >
              <Form.Item
                name="username"
                rules={[{ required: true, message: 'Please input your Username!' }]}
              >
                <Input size="large" prefix={<UserOutlined />} placeholder="Username" />
              </Form.Item>
              <Form.Item
                name="password"
                rules={[{ required: true, message: 'Please input your Password!' }]}
              >
                <Input
                  size="large"
                  prefix={<LockOutlined />}
                  type="password"
                  placeholder="Password"
                />
              </Form.Item>

              <Form.Item>
                <Button type="primary" size="large" htmlType="submit" block>
                  Log in
                </Button>
              </Form.Item>
            </Form>
          </div>
        </div>
      </div>
    </div>
  );
}
Example #8
Source File: Icon.tsx    From html2sketch with MIT License 4 votes vote down vote up
IconSymbol: FC = () => {
  return (
    <Row>
      {/*<CaretUpOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/1.CaretUpOutlined'}*/}
      {/*/>*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.MailOutlined'}*/}
      {/*/>*/}
      {/*<StepBackwardOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
      {/*/>*/}
      {/*<StepForwardOutlined*/}
      {/*  className="icon"*/}
      {/*  symbolName={'1.General/2.Icons/2.StepBackwardOutlined'}*/}
      {/*/>*/}
      <StepForwardOutlined />
      <ShrinkOutlined />
      <ArrowsAltOutlined />
      <DownOutlined />
      <UpOutlined />
      <LeftOutlined />
      <RightOutlined />
      <CaretUpOutlined />
      <CaretDownOutlined />
      <CaretLeftOutlined />
      <CaretRightOutlined />
      <VerticalAlignTopOutlined />
      <RollbackOutlined />
      <FastBackwardOutlined />
      <FastForwardOutlined />
      <DoubleRightOutlined />
      <DoubleLeftOutlined />
      <VerticalLeftOutlined />
      <VerticalRightOutlined />
      <VerticalAlignMiddleOutlined />
      <VerticalAlignBottomOutlined />
      <ForwardOutlined />
      <BackwardOutlined />
      <EnterOutlined />
      <RetweetOutlined />
      <SwapOutlined />
      <SwapLeftOutlined />
      <SwapRightOutlined />
      <ArrowUpOutlined />
      <ArrowDownOutlined />
      <ArrowLeftOutlined />
      <ArrowRightOutlined />
      <LoginOutlined />
      <LogoutOutlined />
      <MenuFoldOutlined />
      <MenuUnfoldOutlined />
      <BorderBottomOutlined />
      <BorderHorizontalOutlined />
      <BorderInnerOutlined />
      <BorderOuterOutlined />
      <BorderLeftOutlined />
      <BorderRightOutlined />
      <BorderTopOutlined />
      <BorderVerticleOutlined />
      <PicCenterOutlined />
      <PicLeftOutlined />
      <PicRightOutlined />
      <RadiusBottomleftOutlined />
      <RadiusBottomrightOutlined />
      <RadiusUpleftOutlined />
      <RadiusUprightOutlined />
      <FullscreenOutlined />
      <FullscreenExitOutlined />
      <QuestionOutlined />
      <PauseOutlined />
      <MinusOutlined />
      <PauseCircleOutlined />
      <InfoOutlined />
      <CloseOutlined />
      <ExclamationOutlined />
      <CheckOutlined />
      <WarningOutlined />
      <IssuesCloseOutlined />
      <StopOutlined />
      <EditOutlined />
      <CopyOutlined />
      <ScissorOutlined />
      <DeleteOutlined />
      <SnippetsOutlined />
      <DiffOutlined />
      <HighlightOutlined />
      <AlignCenterOutlined />
      <AlignLeftOutlined />
      <AlignRightOutlined />
      <BgColorsOutlined />
      <BoldOutlined />
      <ItalicOutlined />
      <UnderlineOutlined />
      <StrikethroughOutlined />
      <RedoOutlined />
      <UndoOutlined />
      <ZoomInOutlined />
      <ZoomOutOutlined />
      <FontColorsOutlined />
      <FontSizeOutlined />
      <LineHeightOutlined />
      <SortAscendingOutlined />
      <SortDescendingOutlined />
      <DragOutlined />
      <OrderedListOutlined />
      <UnorderedListOutlined />
      <RadiusSettingOutlined />
      <ColumnWidthOutlined />
      <ColumnHeightOutlined />
      <AreaChartOutlined />
      <PieChartOutlined />
      <BarChartOutlined />
      <DotChartOutlined />
      <LineChartOutlined />
      <RadarChartOutlined />
      <HeatMapOutlined />
      <FallOutlined />
      <RiseOutlined />
      <StockOutlined />
      <BoxPlotOutlined />
      <FundOutlined />
      <SlidersOutlined />
      <AndroidOutlined />
      <AppleOutlined />
      <WindowsOutlined />
      <IeOutlined />
      <ChromeOutlined />
      <GithubOutlined />
      <AliwangwangOutlined />
      <DingdingOutlined />
      <WeiboSquareOutlined />
      <WeiboCircleOutlined />
      <TaobaoCircleOutlined />
      <Html5Outlined />
      <WeiboOutlined />
      <TwitterOutlined />
      <WechatOutlined />
      <AlipayCircleOutlined />
      <TaobaoOutlined />
      <SkypeOutlined />
      <FacebookOutlined />
      <CodepenOutlined />
      <CodeSandboxOutlined />
      <AmazonOutlined />
      <GoogleOutlined />
      <AlipayOutlined />
      <AntDesignOutlined />
      <AntCloudOutlined />
      <ZhihuOutlined />
      <SlackOutlined />
      <SlackSquareOutlined />
      <BehanceSquareOutlined />
      <DribbbleOutlined />
      <DribbbleSquareOutlined />
      <InstagramOutlined />
      <YuqueOutlined />
      <AlibabaOutlined />
      <YahooOutlined />
      <RedditOutlined />
      <SketchOutlined />
      <AccountBookOutlined />
      <AlertOutlined />
      <ApartmentOutlined />
      <ApiOutlined />
      <QqOutlined />
      <MediumWorkmarkOutlined />
      <GitlabOutlined />
      <MediumOutlined />
      <GooglePlusOutlined />
      <AppstoreAddOutlined />
      <AppstoreOutlined />
      <AudioOutlined />
      <AudioMutedOutlined />
      <AuditOutlined />
      <BankOutlined />
      <BarcodeOutlined />
      <BarsOutlined />
      <BellOutlined />
      <BlockOutlined />
      <BookOutlined />
      <BorderOutlined />
      <BranchesOutlined />
      <BuildOutlined />
      <BulbOutlined />
      <CalculatorOutlined />
      <CalendarOutlined />
      <CameraOutlined />
      <CarOutlined />
      <CarryOutOutlined />
      <CiCircleOutlined />
      <CiOutlined />
      <CloudOutlined />
      <ClearOutlined />
      <ClusterOutlined />
      <CodeOutlined />
      <CoffeeOutlined />
      <CompassOutlined />
      <CompressOutlined />
      <ContactsOutlined />
      <ContainerOutlined />
      <ControlOutlined />
      <CopyrightCircleOutlined />
      <CopyrightOutlined />
      <CreditCardOutlined />
      <CrownOutlined />
      <CustomerServiceOutlined />
      <DashboardOutlined />
      <DatabaseOutlined />
      <DeleteColumnOutlined />
      <DeleteRowOutlined />
      <DisconnectOutlined />
      <DislikeOutlined />
      <DollarCircleOutlined />
      <DollarOutlined />
      <DownloadOutlined />
      <EllipsisOutlined />
      <EnvironmentOutlined />
      <EuroCircleOutlined />
      <EuroOutlined />
      <ExceptionOutlined />
      <ExpandAltOutlined />
      <ExpandOutlined />
      <ExperimentOutlined />
      <ExportOutlined />
      <EyeOutlined />
      <FieldBinaryOutlined />
      <FieldNumberOutlined />
      <FieldStringOutlined />
      <DesktopOutlined />
      <DingtalkOutlined />
      <FileAddOutlined />
      <FileDoneOutlined />
      <FileExcelOutlined />
      <FileExclamationOutlined />
      <FileOutlined />
      <FileImageOutlined />
      <FileJpgOutlined />
      <FileMarkdownOutlined />
      <FilePdfOutlined />
      <FilePptOutlined />
      <FileProtectOutlined />
      <FileSearchOutlined />
      <FileSyncOutlined />
      <FileTextOutlined />
      <FileUnknownOutlined />
      <FileWordOutlined />
      <FilterOutlined />
      <FireOutlined />
      <FlagOutlined />
      <FolderAddOutlined />
      <FolderOutlined />
      <FolderOpenOutlined />
      <ForkOutlined />
      <FormatPainterOutlined />
      <FrownOutlined />
      <FunctionOutlined />
      <FunnelPlotOutlined />
      <GatewayOutlined />
      <GifOutlined />
      <GiftOutlined />
      <GlobalOutlined />
      <GoldOutlined />
      <GroupOutlined />
      <HddOutlined />
      <HeartOutlined />
      <HistoryOutlined />
      <HomeOutlined />
      <HourglassOutlined />
      <IdcardOutlined />
      <ImportOutlined />
      <InboxOutlined />
      <InsertRowAboveOutlined />
      <InsertRowBelowOutlined />
      <InsertRowLeftOutlined />
      <InsertRowRightOutlined />
      <InsuranceOutlined />
      <InteractionOutlined />
      <KeyOutlined />
      <LaptopOutlined />
      <LayoutOutlined />
      <LikeOutlined />
      <LineOutlined />
      <LinkOutlined />
      <Loading3QuartersOutlined />
      <LoadingOutlined />
      <LockOutlined />
      <MailOutlined />
      <ManOutlined />
      <MedicineBoxOutlined />
      <MehOutlined />
      <MenuOutlined />
      <MergeCellsOutlined />
      <MessageOutlined />
      <MobileOutlined />
      <MoneyCollectOutlined />
      <MonitorOutlined />
      <MoreOutlined />
      <NodeCollapseOutlined />
      <NodeExpandOutlined />
      <NodeIndexOutlined />
      <NotificationOutlined />
      <NumberOutlined />
      <PaperClipOutlined />
      <PartitionOutlined />
      <PayCircleOutlined />
      <PercentageOutlined />
      <PhoneOutlined />
      <PictureOutlined />
      <PoundCircleOutlined />
      <PoundOutlined />
      <PoweroffOutlined />
      <PrinterOutlined />
      <ProfileOutlined />
      <ProjectOutlined />
      <PropertySafetyOutlined />
      <PullRequestOutlined />
      <PushpinOutlined />
      <QrcodeOutlined />
      <ReadOutlined />
      <ReconciliationOutlined />
      <RedEnvelopeOutlined />
      <ReloadOutlined />
      <RestOutlined />
      <RobotOutlined />
      <RocketOutlined />
      <SafetyCertificateOutlined />
      <SafetyOutlined />
      <ScanOutlined />
      <ScheduleOutlined />
      <SearchOutlined />
      <SecurityScanOutlined />
      <SelectOutlined />
      <SendOutlined />
      <SettingOutlined />
      <ShakeOutlined />
      <ShareAltOutlined />
      <ShopOutlined />
      <ShoppingCartOutlined />
      <ShoppingOutlined />
      <SisternodeOutlined />
      <SkinOutlined />
      <SmileOutlined />
      <SolutionOutlined />
      <SoundOutlined />
      <SplitCellsOutlined />
      <StarOutlined />
      <SubnodeOutlined />
      <SyncOutlined />
      <TableOutlined />
      <TabletOutlined />
      <TagOutlined />
      <TagsOutlined />
      <TeamOutlined />
      <ThunderboltOutlined />
      <ToTopOutlined />
      <ToolOutlined />
      <TrademarkCircleOutlined />
      <TrademarkOutlined />
      <TransactionOutlined />
      <TrophyOutlined />
      <UngroupOutlined />
      <UnlockOutlined />
      <UploadOutlined />
      <UsbOutlined />
      <UserAddOutlined />
      <UserDeleteOutlined />
      <UserOutlined />
      <UserSwitchOutlined />
      <UsergroupAddOutlined />
      <UsergroupDeleteOutlined />
      <VideoCameraOutlined />
      <WalletOutlined />
      <WifiOutlined />
      <BorderlessTableOutlined />
      <WomanOutlined />
      <BehanceOutlined />
      <DropboxOutlined />
      <DeploymentUnitOutlined />
      <UpCircleOutlined />
      <DownCircleOutlined />
      <LeftCircleOutlined />
      <RightCircleOutlined />
      <UpSquareOutlined />
      <DownSquareOutlined />
      <LeftSquareOutlined />
      <RightSquareOutlined />
      <PlayCircleOutlined />
      <QuestionCircleOutlined />
      <PlusCircleOutlined />
      <PlusSquareOutlined />
      <MinusSquareOutlined />
      <MinusCircleOutlined />
      <InfoCircleOutlined />
      <ExclamationCircleOutlined />
      <CloseCircleOutlined />
      <CloseSquareOutlined />
      <CheckCircleOutlined />
      <CheckSquareOutlined />
      <ClockCircleOutlined />
      <FormOutlined />
      <DashOutlined />
      <SmallDashOutlined />
      <YoutubeOutlined />
      <CodepenCircleOutlined />
      <AliyunOutlined />
      <PlusOutlined />
      <LinkedinOutlined />
      <AimOutlined />
      <BugOutlined />
      <CloudDownloadOutlined />
      <CloudServerOutlined />
      <CloudSyncOutlined />
      <CloudUploadOutlined />
      <CommentOutlined />
      <ConsoleSqlOutlined />
      <EyeInvisibleOutlined />
      <FileGifOutlined />
      <DeliveredProcedureOutlined />
      <FieldTimeOutlined />
      <FileZipOutlined />
      <FolderViewOutlined />
      <FundProjectionScreenOutlined />
      <FundViewOutlined />
      <MacCommandOutlined />
      <PlaySquareOutlined />
      <OneToOneOutlined />
      <RotateLeftOutlined />
      <RotateRightOutlined />
      <SaveOutlined />
      <SwitcherOutlined />
      <TranslationOutlined />
      <VerifiedOutlined />
      <VideoCameraAddOutlined />
      <WhatsAppOutlined />

      {/*</Col>*/}
    </Row>
  );
}
Example #9
Source File: index.tsx    From anew-server with MIT License 4 votes vote down vote up
Login: React.FC = () => {
  const [submitting, setSubmitting] = useState(false);
  const { initialState, setInitialState } = useModel('@@initialState');

  const fetchUserInfo = async () => {
    const userInfo = await initialState?.fetchUserInfo?.();

    if (userInfo) {
      setInitialState({ ...initialState, currentUser: userInfo });
    }
  };

  const handleSubmit = async (values: API.LoginParams) => {
    setSubmitting(true);

    try {
      // 登录
      const login = await AuthLogin(values);

      if (login.status) {
        const defaultloginSuccessMessage = '登录成功';
        message.success(defaultloginSuccessMessage);
        localStorage.setItem('token', login.data.token);
        localStorage.setItem('expires', login.data.expires);
        await fetchUserInfo();
        goto();
        return;
      } // 如果失败去设置用户错误信息
    } catch (error) {
      // 全局状态已处理,这里返回
      return
    }

    setSubmitting(false);
  };

  return (
    <div className={styles.container}>
      <div className={styles.content}>
        <div className={styles.top}>
          <div className={styles.header}>
            <Link to="/">
              <img alt="logo" className={styles.logo} src="/logo.svg" />
              <span className={styles.title}>Anew-Server</span>
            </Link>
          </div>
          <div className={styles.desc}>{'运维平台'}</div>
        </div>

        <div className={styles.main}>
          <ProForm
            initialValues={{
              autoLogin: true,
            }}
            submitter={{
              searchConfig: {
                submitText: '登录',
              },
              render: (_, dom) => dom.pop(),
              submitButtonProps: {
                loading: submitting,
                size: 'large',
                style: {
                  width: '100%',
                },
              },
            }}
            onFinish={async (values) => {
              handleSubmit(values as API.LoginParams);
            }}
          >
            <>
              <ProFormText
                name="username"
                fieldProps={{
                  size: 'large',
                  prefix: <UserOutlined className={styles.prefixIcon} />,
                }}
                placeholder={'用户名: admin or user'}
                rules={[
                  {
                    required: true,
                    message: '用户名是必填项!',
                  },
                ]}
              />
              <ProFormText.Password
                name="password"
                fieldProps={{
                  size: 'large',
                  prefix: <LockOutlined className={styles.prefixIcon} />,
                }}
                placeholder={'密码: ant.design'}
                rules={[
                  {
                    required: true,
                    message: '密码是必填项!',
                  },
                ]}
              />
            </>
          </ProForm>
        </div>
      </div>
      <Footer />
    </div>
  );
}
Example #10
Source File: WidgetActionDropdown.tsx    From datart with Apache License 2.0 4 votes vote down vote up
WidgetActionDropdown: React.FC<WidgetActionDropdownProps> = memo(
  ({ widget }) => {
    const { editing: boardEditing } = useContext(BoardContext);

    const widgetAction = useWidgetAction();
    const dataChart = useContext(WidgetChartContext)!;
    const t = useI18NPrefix(`viz.widget.action`);
    const menuClick = useCallback(
      ({ key }) => {
        widgetAction(key, widget);
      },
      [widgetAction, widget],
    );
    const getAllList = useCallback(() => {
      const allWidgetActionList: WidgetActionListItem<widgetActionType>[] = [
        {
          key: 'refresh',
          label: t('refresh'),
          icon: <SyncOutlined />,
        },
        {
          key: 'fullScreen',
          label: t('fullScreen'),
          icon: <FullscreenOutlined />,
        },
        {
          key: 'edit',
          label: t('edit'),
          icon: <EditOutlined />,
        },
        {
          key: 'delete',
          label: t('delete'),
          icon: <DeleteOutlined />,
          danger: true,
        },

        {
          key: 'info',
          label: t('info'),
          icon: <InfoOutlined />,
        },
        {
          key: 'lock',
          label: t('lock'),
          icon: <LockOutlined />,
        },

        {
          key: 'makeLinkage',
          label: t('makeLinkage'),
          icon: <LinkOutlined />,
          divider: true,
        },
        {
          key: 'closeLinkage',
          label: t('closeLinkage'),
          icon: <CloseCircleOutlined />,
          danger: true,
        },
        {
          key: 'makeJump',
          label: t('makeJump'),
          icon: <BranchesOutlined />,
          divider: true,
        },
        {
          key: 'closeJump',
          label: t('closeJump'),
          icon: <CloseCircleOutlined />,
          danger: true,
        },
      ];
      return allWidgetActionList;
    }, [t]);
    const actionList = useMemo(() => {
      return (
        getWidgetActionList({
          allList: getAllList(),
          widget,
          boardEditing,
          chartGraphId: dataChart?.config?.chartGraphId,
        }) || []
      );
    }, [boardEditing, dataChart?.config?.chartGraphId, getAllList, widget]);
    const dropdownList = useMemo(() => {
      const menuItems = actionList.map(item => {
        return (
          <React.Fragment key={item.key}>
            {item.divider && <Menu.Divider />}
            <Menu.Item
              danger={item.danger}
              icon={item.icon}
              disabled={item.disabled}
              key={item.key}
            >
              {item.label}
            </Menu.Item>
          </React.Fragment>
        );
      });

      return <Menu onClick={menuClick}>{menuItems}</Menu>;
    }, [actionList, menuClick]);
    if (actionList.length === 0) {
      return null;
    }
    return (
      <Dropdown
        className="widget-tool-dropdown"
        overlay={dropdownList}
        placement="bottomCenter"
        trigger={['click']}
        arrow
      >
        <Button icon={<EllipsisOutlined />} type="link" />
      </Dropdown>
    );
  },
)
Example #11
Source File: index.tsx    From fe-v5 with Apache License 2.0 4 votes vote down vote up
export default function Login() {
  const { t } = useTranslation();
  const [form] = Form.useForm();
  const history = useHistory();
  const location = useLocation();
  const redirect = location.search && new URLSearchParams(location.search).get('redirect');
  const dispatch = useDispatch();

  const handleSubmit = async () => {
    try {
      await form.validateFields();
      login();
    } catch {
      console.log(t('输入有误'));
    }
  };

  const login = async () => {
    let { username, password } = form.getFieldsValue();
    const err = await dispatch({
      type: 'account/login',
      username,
      password,
    });

    if (!err) {
      history.push(redirect || '/metric/explorer');
    }
  };

  return (
    <div className='login-warp'>
      <div className='banner'>
        <div className='banner-bg'>
          <img src={'/image/logo-l.svg'} className='logo' width='132'></img>
        </div>
      </div>
      <div className='login-panel'>
        <div className='login-main'>
          <div className='login-title'>Nightingale</div>
          <Form form={form} layout='vertical' requiredMark={true}>
            <Form.Item
              required
              name='username'
              rules={[
                {
                  required: true,
                  message: t('请输入用户名'),
                },
              ]}
            >
              <Input placeholder={t('请输入用户名')} prefix={<UserOutlined className='site-form-item-icon' />} />
            </Form.Item>
            <Form.Item
              required
              name='password'
              rules={[
                {
                  required: true,
                  message: t('请输入密码'),
                },
              ]}
            >
              <Input type='password' placeholder={t('请输入密码')} onPressEnter={handleSubmit} prefix={<LockOutlined className='site-form-item-icon' />} />
            </Form.Item>

            <Form.Item>
              <Button type='primary' onClick={handleSubmit}>
                {t('登录')}
              </Button>
            </Form.Item>
            <div className='login-other'>
              <strong>其他登录方式:</strong>
              <a
                onClick={() => {
                  getRedirectURL().then((res) => {
                    if (res.dat) {
                      window.location.href = res.dat;
                    } else {
                      message.warning('没有配置 OIDC 登录地址!');
                    }
                  });
                }}
              >
                OIDC
              </a>
            </div>
          </Form>
        </div>
      </div>
    </div>
  );
}
Example #12
Source File: index.tsx    From foodie with MIT License 4 votes vote down vote up
PostItem: React.FC<IProps> = (props) => {
    const { post, likeCallback, isAuth } = props;
    const [isCommentVisible, setCommentVisible] = useState(false);
    const deleteModal = useModal();
    const updateModal = useModal();
    const commentInputRef = useRef<HTMLInputElement | null>(null);
    const dispatch = useDispatch();

    const handleToggleComment = () => {
        if (!isAuth) return;
        if (!isCommentVisible) setCommentVisible(true);
        if (commentInputRef.current) commentInputRef.current.focus();
    }

    const displayLikeMetric = (likesCount: number, isLiked: boolean) => {
        const like = likesCount > 1 ? 'like' : 'likes';
        const likeMinusSelf = (likesCount - 1) > 1 ? 'like' : 'likes';
        const people = likesCount > 1 ? 'people' : 'person';
        const peopleMinusSelf = (likesCount - 1) > 1 ? 'people' : 'person';

        if (isLiked && likesCount <= 1) {
            return 'You like this.'
        } else if (isLiked && likesCount > 1) {
            return `You and ${likesCount - 1} other ${peopleMinusSelf} ${likeMinusSelf} this.`;
        } else {
            return `${likesCount} ${people} ${like} this.`;
        }
    }

    const handleClickLikes = () => {
        if (isAuth) {
            dispatch(showModal(EModalType.POST_LIKES));
            dispatch(setTargetPost(props.post));
        }
    }

    const handleClickPrivacyChange = () => {
        if (post.isOwnPost) {
            dispatch(setTargetPost(post));
            dispatch(showModal(EModalType.EDIT_POST));
        }
    }

    return (
        <div className="flex flex-col bg-white rounded-lg my-4 p-4 first:mt-0 shadow-lg dark:bg-indigo-1000">
            {/* --- AVATAR AND OPTIONS */}
            <div className="flex justify-between items-center w-full">
                <div className="flex">
                    <Avatar
                        url={post.author.profilePicture?.url}
                        className="mr-3"
                    />
                    <div className="flex flex-col">
                        <Link className="dark:text-indigo-400" to={`/user/${post.author.username}`}>
                            <h5 className="font-bold">{post.author.username}</h5>
                        </Link>
                        <div className="flex items-center space-x-1">
                            <span className="text-sm text-gray-500">{dayjs(post.createdAt).fromNow()}</span>
                            <div
                                className={`w-4 h-4 rounded-full flex items-center justify-center ${post.isOwnPost && 'cursor-pointer hover:bg-gray-100 dark:hover:bg-indigo-900'}`}
                                onClick={handleClickPrivacyChange}
                                title={post.isOwnPost ? 'Change Privacy' : ''}
                            >
                                {post.privacy === 'private'
                                    ? <LockOutlined className="text-xs text-gray-500 dark:text-white" />
                                    : post.privacy === 'follower'
                                        ? <UserOutlined className="text-xs text-gray-500 dark:text-white" />
                                        : <GlobalOutlined className="text-xs text-gray-500 dark:text-white" />
                                }
                            </div>
                        </div>
                    </div>
                </div>
                {isAuth && (
                    <PostOptions
                        openDeleteModal={deleteModal.openModal}
                        openUpdateModal={updateModal.openModal}
                        post={post}
                    />
                )}
            </div>
            {/* --- DESCRIPTION */}
            <div className="mb-3 mt-2">
                <p className="text-gray-700 dark:text-gray-300 break-words">{post.description}</p>
            </div>
            {/* --- IMAGE GRID ----- */}
            {post.photos.length !== 0 && <ImageGrid images={post.photos.map(img => img.url)} />}
            {/* ---- LIKES/COMMENTS DETAILS ---- */}
            <div className="flex justify-between px-2 my-2">
                <div onClick={handleClickLikes}>
                    {post.likesCount > 0 && (
                        <span className="text-gray-500 text-sm cursor-pointer hover:underline hover:text-gray-800 dark:hover:text-white">
                            {displayLikeMetric(post.likesCount, post.isLiked)}
                        </span>
                    )}
                </div>
                {/* --- COMMENTS COUNT ----- */}
                <div>
                    {post.commentsCount > 0 && (
                        <span
                            className="text-gray-500 hover:text-gray-800 cursor-pointer text-sm hover:underline dark:text-gray-500 dark:hover:text-white"
                            onClick={handleToggleComment}
                        >
                            {post.commentsCount} {post.commentsCount === 1 ? 'comment' : 'comments'}
                        </span>
                    )}
                </div>
            </div>
            {/* --- LIKE/COMMENT BUTTON */}
            {isAuth ? (
                <div className="flex items-center justify-around py-2 border-t border-gray-200 dark:border-gray-800">
                    <LikeButton postID={post.id} isLiked={post.isLiked} likeCallback={likeCallback} />
                    <span
                        className="py-2 rounded-md flex items-center justify-center text-gray-700 hover:text-gray-800 700 dark:text-gray-400 dark:hover:text-white dark:hover:bg-indigo-1100 cursor-pointer hover:bg-gray-100 text-l w-2/4"
                        onClick={handleToggleComment}
                    >
                        <CommentOutlined />&nbsp;Comment
                    </span>
                </div>
            ) : (
                <div className="text-center py-2">
                    <span className="text-gray-400 text-sm">
                        <Link className="font-medium underline dark:text-indigo-400" to={LOGIN}>Login</Link> to like or comment on post.
                    </span>
                </div>
            )}
            {isAuth && (
                <Suspense fallback={<LoadingOutlined className="text-gray-800 dark:text-white" />}>
                    <Comments
                        postID={post.id}
                        authorID={post.author.id}
                        isCommentVisible={isCommentVisible}
                        commentInputRef={commentInputRef}
                        setInputCommentVisible={setCommentVisible}
                    />
                </Suspense>
            )}
        </div>
    );
}
Example #13
Source File: index.tsx    From ant-design-pro-V4 with MIT License 4 votes vote down vote up
Login: React.FC<LoginProps> = (props) => {
  const { userLogin = {}, submitting } = props;
  const { status, type: loginType } = userLogin;
  const [type, setType] = useState<string>('account');
  const intl = useIntl();

  const handleSubmit = (values: LoginParamsType) => {
    const { dispatch } = props;
    dispatch({
      type: 'login/login',
      payload: { ...values, type },
    });
  };
  return (
    <div className={styles.main}>
      <ProForm
        initialValues={{
          autoLogin: true,
        }}
        submitter={{
          render: (_, dom) => dom.pop(),
          submitButtonProps: {
            loading: submitting,
            size: 'large',
            style: {
              width: '100%',
            },
          },
        }}
        onFinish={(values) => {
          handleSubmit(values as LoginParamsType);
          return Promise.resolve();
        }}
      >
        <Tabs activeKey={type} onChange={setType}>
          <Tabs.TabPane
            key="account"
            tab={intl.formatMessage({
              id: 'pages.login.accountLogin.tab',
              defaultMessage: 'Account password login',
            })}
          />
          <Tabs.TabPane
            key="mobile"
            tab={intl.formatMessage({
              id: 'pages.login.phoneLogin.tab',
              defaultMessage: 'Mobile phone number login',
            })}
          />
        </Tabs>

        {status === 'error' && loginType === 'account' && !submitting && (
          <LoginMessage
            content={intl.formatMessage({
              id: 'pages.login.accountLogin.errorMessage',
              defaultMessage: 'Incorrect account or password(admin/ant.design)',
            })}
          />
        )}
        {type === 'account' && (
          <>
            <ProFormText
              name="userName"
              fieldProps={{
                size: 'large',
                prefix: <UserOutlined className={styles.prefixIcon} />,
              }}
              placeholder={intl.formatMessage({
                id: 'pages.login.username.placeholder',
                defaultMessage: 'Username: admin or user',
              })}
              rules={[
                {
                  required: true,
                  message: (
                    <FormattedMessage
                      id="pages.login.username.required"
                      defaultMessage="Please enter user name!"
                    />
                  ),
                },
              ]}
            />
            <ProFormText.Password
              name="password"
              fieldProps={{
                size: 'large',
                prefix: <LockOutlined className={styles.prefixIcon} />,
              }}
              placeholder={intl.formatMessage({
                id: 'pages.login.password.placeholder',
                defaultMessage: 'Password: ant.design',
              })}
              rules={[
                {
                  required: true,
                  message: (
                    <FormattedMessage
                      id="pages.login.password.required"
                      defaultMessage="Please enter password!"
                    />
                  ),
                },
              ]}
            />
          </>
        )}

        {status === 'error' && loginType === 'mobile' && !submitting && (
          <LoginMessage content="Verification code error" />
        )}
        {type === 'mobile' && (
          <>
            <ProFormText
              fieldProps={{
                size: 'large',
                prefix: <MobileOutlined className={styles.prefixIcon} />,
              }}
              name="mobile"
              placeholder={intl.formatMessage({
                id: 'pages.login.phoneNumber.placeholder',
                defaultMessage: 'Phone number',
              })}
              rules={[
                {
                  required: true,
                  message: (
                    <FormattedMessage
                      id="pages.login.phoneNumber.required"
                      defaultMessage="Please enter phone number!"
                    />
                  ),
                },
                {
                  pattern: /^1\d{10}$/,
                  message: (
                    <FormattedMessage
                      id="pages.login.phoneNumber.invalid"
                      defaultMessage="Malformed phone number!"
                    />
                  ),
                },
              ]}
            />
            <ProFormCaptcha
              fieldProps={{
                size: 'large',
                prefix: <MailOutlined className={styles.prefixIcon} />,
              }}
              captchaProps={{
                size: 'large',
              }}
              placeholder={intl.formatMessage({
                id: 'pages.login.captcha.placeholder',
                defaultMessage: 'Please enter verification code',
              })}
              captchaTextRender={(timing, count) => {
                if (timing) {
                  return `${count} ${intl.formatMessage({
                    id: 'pages.getCaptchaSecondText',
                    defaultMessage: 'Get verification code',
                  })}`;
                }
                return intl.formatMessage({
                  id: 'pages.login.phoneLogin.getVerificationCode',
                  defaultMessage: 'Get verification code',
                });
              }}
              name="captcha"
              rules={[
                {
                  required: true,
                  message: (
                    <FormattedMessage
                      id="pages.login.captcha.required"
                      defaultMessage="Please enter verification code!"
                    />
                  ),
                },
              ]}
              onGetCaptcha={async (mobile) => {
                const result = await getFakeCaptcha(mobile);
                if (result === false) {
                  return;
                }
                message.success(
                  'Get the verification code successfully! The verification code is: 1234',
                );
              }}
            />
          </>
        )}
        <div
          style={{
            marginBottom: 24,
          }}
        >
          <ProFormCheckbox noStyle name="autoLogin">
            <FormattedMessage id="pages.login.rememberMe" defaultMessage="Auto login" />
          </ProFormCheckbox>
          <a
            style={{
              float: 'right',
            }}
          >
            <FormattedMessage id="pages.login.forgotPassword" defaultMessage="Forget password" />
          </a>
        </div>
      </ProForm>
      <Space className={styles.other}>
        <FormattedMessage id="pages.login.loginWith" defaultMessage="Other login methods" />
        <AlipayCircleOutlined className={styles.icon} />
        <TaobaoCircleOutlined className={styles.icon} />
        <WeiboCircleOutlined className={styles.icon} />
      </Space>
    </div>
  );
}
Example #14
Source File: GeneralSignup.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
export function GeneralSignup(props: GeneralSignupProps): React.ReactElement {
  const [form] = Form.useForm();
  const runtime = getRuntime();
  const brand = runtime.getBrandSettings();
  const enabledFeatures = runtime.getFeatureFlags();
  const { t } = useTranslation(NS_GENERAL_AUTH);
  const [, setForceUpdate] = useState<any>();

  const passwordConfigMap = {
    default: {
      regex: /^.{6,20}$/,
      description: "请输入6至20位密码",
    },
    strong: {
      regex: /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9]).{8,20}$/,
      description: "请输入8至20位密码,且同时包含大小写字母、数字、特殊字符",
    },
    backend: {},
  };
  let passwordLevel: keyof typeof passwordConfigMap = "default"; //特性开关
  useEffect(() => {
    if (enabledFeatures["enable-backend-password-config"]) {
      (async () => {
        passwordLevel = "backend";
        passwordConfigMap[passwordLevel] =
          await UserAdminApi_getPasswordConfig();
      })();
    }
  }, []);

  const MIN_USERNAME_LENGTH = 3; //特性开关
  const MAX_USERNAME_LENGTH = 32; //特性开关
  const usernamePattern = new RegExp(
    `^[A-Za-z0-9][A-Za-z0-9|_\\-\\.]{${MIN_USERNAME_LENGTH - 1},${
      MAX_USERNAME_LENGTH - 1
    }}$`
  );

  const iniviteCodePattern = /^[0-9a-zA-Z]{9}$/;
  const hideInvite = iniviteCodePattern.test(getInviteCode());
  const [isCommonSignup, setIsCommonSignup] = useState(true);

  const [isTermsVisible, setIsTermsVisible] = useState(false);

  function showTerms(): void {
    setIsTermsVisible(true);
  }
  function hideTerms(): void {
    setIsTermsVisible(false);
  }
  function agreeTerms(): void {
    form.setFieldsValue({
      terms: true,
    });
    hideTerms();
  }
  function disagreeTerms(): void {
    form.setFieldsValue({
      terms: false,
    });
    hideTerms();
  }

  const [imageHeight, setImageHeight] = useState(window.innerHeight);
  const onWindowResized = () => {
    if (imageHeight < window.innerHeight) {
      setImageHeight(window.innerHeight);
    }
  };
  useEffect(() => {
    const handleWindowResized = debounce(onWindowResized, 500, {
      leading: false,
    });
    window.addEventListener("resize", handleWindowResized);
    return () => {
      window.removeEventListener("resize", handleWindowResized);
    };
  }, []);

  const timer = useRef<any>();
  const count = useRef<number>(duration);
  const [verifyBtnDisabled, setVerifyBtnDisabled] = useState(true);
  const [content, setContent] = useState(t(K.GET_VERIFY_CODE));
  const [messageId, setMessageId] = useState("");
  const handleVerifyBtnClick = async (
    e: React.MouseEvent<HTMLElement, MouseEvent>
  ) => {
    if (timer.current) return;
    count.current -= 1;
    setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
    setVerifyBtnDisabled(true);
    timer.current = setInterval(() => {
      count.current -= 1;
      setContent(t(K.GET_VERIFY_CODE_TIPS, { count: count.current }));
      if (count.current === 0) {
        clearInterval(timer.current);
        timer.current = null;
        count.current = duration;
        setVerifyBtnDisabled(false);
        setContent(t(K.GET_VERIFY_CODE));
      }
    }, 1000);
    const result = await CustomerApi_sendApplicationVerificationCode({
      phone_number: form.getFieldValue("phone"),
    });
    result.message_id && setMessageId(result.message_id);
  };

  const redirect = async (result: Record<string, any>): Promise<void> => {
    runtime.reloadSharedData();
    await runtime.reloadMicroApps();
    resetLegacyIframe();
    authenticate({
      org: result.org,
      username: result.username,
      userInstanceId: result.userInstanceId,
      accessRule: result.accessRule,
    });
    const { state } = getHistory().location;
    const from =
      state && state.from
        ? state.from
        : {
            pathname: "/",
          };
    const redirect = createLocation(from);
    getHistory().push(redirect);
  };

  const onFinish = async (values: Record<string, any>): Promise<void> => {
    values.password = encryptValue(values.password);
    try {
      let result: Record<string, any>;
      if (isCommonSignup && !hideInvite) {
        result = await OrgApi_saaSOrgRegister(
          assign(omit(values, ["terms", "password2"]), {
            message_id: messageId,
          }) as OrgApi_SaaSOrgRegisterRequestBody
        );
      } else {
        result = await AuthApi_register(
          assign(
            omit(values, ["terms", "password2", "username"]),
            hideInvite
              ? { invite: getInviteCode(), name: values["username"] }
              : { name: values["username"] }
          ) as AuthApi_RegisterRequestBody
        );
      }
      if (result.loggedIn) {
        redirect(result);
      }
      message.success(t(K.REGISTER_SUCCESS));
    } catch (error) {
      Modal.error({
        title: t(K.REGISTER_FAILED),
        content:
          isCommonSignup && !hideInvite
            ? t(K.WRONG_VERIFICATION_CODE)
            : t(K.WRONG_INVITE_CODE),
      });
    }
  };

  return (
    <>
      <div className={styles.signupWrapper}>
        <div className={styles.signupHeader}>
          <div className={styles.logoBar}>
            <Link to="/">
              {brand.auth_logo_url ? (
                <img
                  src={brand.auth_logo_url}
                  style={{ height: 32, verticalAlign: "middle" }}
                />
              ) : (
                <Logo height={32} style={{ verticalAlign: "middle" }} />
              )}
            </Link>
          </div>
        </div>
        <div className={styles.signupImg}>
          <img src={loginPng} style={{ height: imageHeight }} />
        </div>
        <div className={styles.signupForm}>
          <Card bordered={false}>
            {!hideInvite &&
              (isCommonSignup ? (
                <a
                  onClick={() => {
                    setIsCommonSignup(false);
                  }}
                  style={{ alignSelf: "flex-end" }}
                  id="JumpToJoinFormLink"
                >
                  {t(K.JOIN_THE_ORGANIZATION)} <RightOutlined />
                </a>
              ) : (
                <a
                  onClick={() => {
                    setIsCommonSignup(true);
                  }}
                  id="JumpToCommonFormLink"
                >
                  <LeftOutlined /> {t(K.REGISTER_COMMONLY)}
                </a>
              ))}
            {!hideInvite && isCommonSignup ? (
              <div className={styles.title}>{t(K.REGISTER_ACCOUNT)}</div>
            ) : (
              <div className={styles.title}>{t(K.REGISTER_AND_JOIN)}</div>
            )}
            <Form name="signupForm" form={form} onFinish={onFinish}>
              <Form.Item
                validateFirst={true}
                name="username"
                rules={[
                  {
                    required: true,
                    message: t(K.USERNAME_TIPS, {
                      minLength: 3,
                      maxLength: 32,
                    }),
                  },
                  {
                    pattern: usernamePattern,
                    message: t(K.USERNAME_TIPS, {
                      minLength: 3,
                      maxLength: 32,
                    }),
                  },
                  {
                    validator: (
                      _: any,
                      value: any,
                      callback: (value?: string) => void
                    ) =>
                      validateMap["airNameValidator"](
                        value,
                        callback,
                        setForceUpdate
                      ),
                  },
                ]}
              >
                <Input
                  prefix={<UserOutlined className={styles.inputPrefixIcon} />}
                  placeholder={t(K.USERNAME)}
                />
              </Form.Item>
              {enabledFeatures["enable-nickname-config"] && hideInvite && (
                <Form.Item validateFirst={false} name="nickname">
                  <Input
                    prefix={
                      <SolutionOutlined className={styles.inputPrefixIcon} />
                    }
                    placeholder={t(K.NICKNAME)}
                  />
                </Form.Item>
              )}
              <Form.Item
                name="email"
                validateFirst={true}
                rules={[
                  { required: true, message: t(K.PLEASE_ENTER_VALID_EMAIL) },
                  { type: "email", message: t(K.PLEASE_ENTER_VALID_EMAIL) },
                  {
                    validator: (
                      _: any,
                      value: any,
                      callback: (value?: string) => void
                    ) =>
                      validateMap["airEmailValidator"](
                        value,
                        callback,
                        setForceUpdate
                      ),
                  },
                ]}
              >
                <Input
                  prefix={<MailOutlined className={styles.inputPrefixIcon} />}
                  type="email"
                  placeholder={t(K.EMAIL)}
                />
              </Form.Item>
              <Form.Item
                validateFirst={true}
                name="password"
                rules={[
                  { required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
                  {
                    pattern: passwordConfigMap[passwordLevel].regex,
                    message: passwordConfigMap[passwordLevel].description,
                  },
                ]}
              >
                <Input
                  prefix={<LockOutlined className={styles.inputPrefixIcon} />}
                  type="password"
                  placeholder={t(K.PASSWORD)}
                />
              </Form.Item>
              <Form.Item
                dependencies={["password"]}
                name="password2"
                rules={[
                  { required: true, message: t(K.PLEASE_INPUT_PASSWORD) },
                  ({ getFieldValue }) => ({
                    validator(_, value) {
                      if (!value || getFieldValue("password") === value) {
                        return Promise.resolve();
                      }
                      return Promise.reject(
                        new Error(t(K.TWO_PASSWORDS_ARE_INCONSISTENT))
                      );
                    },
                  }),
                ]}
              >
                <Input
                  prefix={<LockOutlined className={styles.inputPrefixIcon} />}
                  type="password"
                  placeholder={t(K.PASSWORD_CONFIRM)}
                />
              </Form.Item>
              {!hideInvite &&
                (isCommonSignup ? (
                  <>
                    <Form.Item
                      validateFirst={true}
                      rules={[
                        {
                          required: true,
                          message: t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER),
                        },
                        {
                          validator: (_, value) => {
                            if (
                              /^(?=\d{11}$)^1(?:3\d|4[57]|5[^4\D]|7[^249\D]|8\d)\d{8}$/.test(
                                value
                              )
                            ) {
                              setVerifyBtnDisabled(false);
                              return Promise.resolve();
                            }
                            setVerifyBtnDisabled(true);
                            return Promise.reject(
                              new Error(t(K.PLEASE_FILL_IN_VALID_PHONE_NUMBER))
                            );
                          },
                        },
                      ]}
                      name="phone"
                    >
                      <Input
                        prefix={
                          <PhoneOutlined
                            className={styles.inputPrefixIcon}
                            rotate={90}
                          />
                        }
                        suffix={
                          <Button
                            disabled={verifyBtnDisabled}
                            type="text"
                            onClick={handleVerifyBtnClick}
                            id="verifyBtn"
                          >
                            {content}
                          </Button>
                        }
                        placeholder={t(K.PHONE)}
                      />
                    </Form.Item>
                    <Form.Item
                      rules={[
                        {
                          required: true,
                          message: t(K.PLEASE_INPUT_PHRASE),
                        },
                        {
                          pattern: /^\d{6}$/,
                          message: t(K.PLEASE_INPUT_VALID_PHRASE),
                        },
                      ]}
                      name="verification_code"
                    >
                      <Input
                        prefix={
                          <SafetyOutlined className={styles.inputPrefixIcon} />
                        }
                        placeholder={t(K.VERIFY_CODE)}
                      ></Input>
                    </Form.Item>
                  </>
                ) : (
                  <Form.Item
                    validateFirst={true}
                    name="invite"
                    rules={[
                      {
                        required: true,
                        message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
                      },
                      {
                        pattern: iniviteCodePattern,
                        message: t([K.PLEASE_FILL_IN_INVITE_CODE]),
                      },
                    ]}
                  >
                    <Input
                      prefix={
                        <GeneralIcon
                          icon={{
                            lib: "easyops",
                            icon: "release-management",
                            category: "menu",
                            color: "rgba(0,0,0,.25)",
                          }}
                        />
                      }
                      type="text"
                      placeholder={t(K.INVITE_CODE)}
                    />
                  </Form.Item>
                ))}
              <Form.Item
                name="terms"
                valuePropName="checked"
                rules={[
                  {
                    validator: (_, value) =>
                      value
                        ? Promise.resolve()
                        : Promise.reject(new Error(t(K.AGREE_TERMS_TIPS))),
                  },
                ]}
              >
                <Checkbox>
                  {t(K.AGREE_TERMS)}
                  <a
                    onClick={() => {
                      showTerms();
                    }}
                    id="TermsLink"
                  >
                    {t(K.UWINTECH_TERMS)}
                  </a>
                </Checkbox>
              </Form.Item>
              <Form.Item>
                <Button
                  type="primary"
                  htmlType="submit"
                  style={{
                    width: "100%",
                    height: 34,
                  }}
                  id="submitBtn"
                >
                  {t(K.REGISTER)}
                </Button>
              </Form.Item>
              <Form.Item>
                <div style={{ textAlign: "center" }}>
                  {t(K.ALREADY_HAVE_AN_ACCOUNT)}
                  <a
                    id="LogInLink"
                    onClick={() => {
                      getHistory().push(
                        createLocation({
                          pathname: props.loginUrl ?? "/auth/login",
                        })
                      );
                    }}
                  >
                    {t(K.LOGIN_IMMEDIATELY)}
                  </a>
                </div>
              </Form.Item>
            </Form>
          </Card>
          <Modal
            visible={isTermsVisible}
            title={t(K.UWINTECH_TERMS)}
            width={598}
            okType="default"
            cancelText={t(K.DISAGREE)}
            okText={t(K.AGREE)}
            closable={false}
            onCancel={() => {
              disagreeTerms();
            }}
            onOk={() => {
              agreeTerms();
            }}
          >
            <Terms />
          </Modal>
        </div>
      </div>
    </>
  );
}
Example #15
Source File: GeneralLogin.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
render(): React.ReactNode {
    const { t, form } = this.props;
    const {
      getFieldDecorator,
      getFieldsValue,
      isFieldTouched,
      setFieldsValue,
    } = form;
    const runtime = getRuntime();
    const enabledFeatures = runtime.getFeatureFlags();
    const brand = runtime.getBrandSettings();
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const self = this;
    const notSetField = (fieldValue: string, fieldName: string): boolean => {
      if (fieldValue !== undefined) {
        return !fieldValue.length && isFieldTouched(fieldName);
      } else {
        return false;
      }
    };

    const renderLoginForm = () => {
      return (
        <Form onSubmit={this.handleSubmit}>
          <Tooltip title={this.state.loginErrorMsg}>
            <div className={styles.loginFormError}>
              {this.state.loginErrorMsg}
            </div>
          </Tooltip>
          <Form.Item>
            {getFieldDecorator("username", {
              rules: [
                {
                  validator(rule, value) {
                    const { username, password, phrase } = getFieldsValue();
                    if (!username.length) {
                      if (
                        notSetField(password, "password") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(
                            K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
                          ),
                        });
                      } else if (
                        notSetField(password, "password") &&
                        !notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
                        });
                      } else if (
                        !notSetField(password, "password") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
                        });
                      } else {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
                        });
                      }
                      return Promise.reject("");
                    } else {
                      if (
                        notSetField(password, "password") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
                        });
                      } else if (
                        notSetField(password, "password") &&
                        !notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
                        });
                      } else if (
                        !notSetField(password, "password") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
                        });
                      } else {
                        self.setState({
                          loginErrorMsg: "",
                        });
                      }
                    }
                    return Promise.resolve();
                  },
                },
              ],
            })(
              <Input
                prefix={<UserOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
                placeholder={
                  this.state.currentLoginMethod === "ldap"
                    ? t(K.LDAP_ACCOUNT)
                    : t(K.USERNAME)
                }
              />
            )}
          </Form.Item>
          <Form.Item>
            {getFieldDecorator("password", {
              rules: [
                {
                  validator(rule, value) {
                    const { username, password, phrase } = getFieldsValue();
                    if (!password.length) {
                      if (
                        notSetField(username, "username") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(
                            K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
                          ),
                        });
                      } else if (
                        notSetField(username, "username") &&
                        !notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
                        });
                      } else if (
                        !notSetField(username, "username") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
                        });
                      } else {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
                        });
                      }
                      return Promise.reject("");
                    } else {
                      if (
                        notSetField(username, "username") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
                        });
                      } else if (
                        notSetField(username, "username") &&
                        !notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
                        });
                      } else if (
                        !notSetField(username, "username") &&
                        notSetField(phrase, "phrase")
                      ) {
                        self.setState({
                          loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
                        });
                      } else {
                        self.setState({
                          loginErrorMsg: "",
                        });
                      }
                    }
                    return Promise.resolve();
                  },
                },
              ],
            })(
              <Input
                prefix={<LockOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
                type="password"
                placeholder={t(K.PASSWORD)}
              />
            )}
          </Form.Item>
          {this.state.security_codeEnabled && (
            <Form.Item style={{ bottom: "61px", marginBottom: "24px" }}>
              {getFieldDecorator("phrase", {
                rules: [
                  {
                    validator(rule, value) {
                      const { username, password, phrase } = getFieldsValue();
                      if (!phrase.length) {
                        if (
                          notSetField(username, "username") &&
                          notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(
                              K.PLEASE_INPUT_USERNAME_PASSWORD_PHRASE
                            ),
                          });
                        } else if (
                          notSetField(username, "username") &&
                          !notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PHRASE),
                          });
                        } else if (
                          !notSetField(username, "username") &&
                          notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD_PHRASE),
                          });
                        } else {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_PHRASE),
                          });
                        }
                        return Promise.reject("");
                      } else {
                        if (
                          notSetField(username, "username") &&
                          notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_USERNAME_PASSWORD),
                          });
                        } else if (
                          !notSetField(username, "username") &&
                          notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_PASSWORD),
                          });
                        } else if (
                          notSetField(username, "username") &&
                          !notSetField(password, "password")
                        ) {
                          self.setState({
                            loginErrorMsg: t(K.PLEASE_INPUT_USERNAME),
                          });
                        } else {
                          self.setState({
                            loginErrorMsg: "",
                          });
                        }
                      }
                      return Promise.resolve();
                    },
                  },
                ],
              })(
                <Row>
                  <Input
                    //prefix={<LockOutlined style={{ color: "rgba(0,0,0,.25)" }} />}
                    prefix={
                      <FontAwesomeIcon
                        icon="shield-alt"
                        style={{ color: "rgba(0,0,0,.25)" }}
                      />
                    }
                    style={{
                      width: "50%",
                      height: "42px",
                      verticalAlign: "middle",
                    }}
                    placeholder={t(K.SECURITY_CODE)}
                  />
                  <img
                    src={this.state.yzm}
                    style={{
                      width: "50%",
                      height: "42px",
                      verticalAlign: "middle",
                    }}
                    alt=""
                    onClick={this.handleGetSecurityCodeAgain}
                  />
                </Row>
              )}
            </Form.Item>
          )}
          <Form.Item>
            <Spin spinning={this.state.loggingIn}>
              <Button
                type="primary"
                htmlType="submit"
                style={{
                  width: "100%",
                  height: 34,
                  bottom: this.state.security_codeEnabled ? "-45px" : "0",
                }}
              >
                {t(K.LOGIN)}
              </Button>
            </Spin>
            <div className={styles.loginAppendix}>
              {enabledFeatures["sign-up-for-free-enabled"] && (
                <a
                  href={getRuntime().getBasePath() + "auth/signup"}
                  style={{ display: "block" }}
                >
                  {t(K.REGISTER_ACCOUNT)}
                </a>
              )}
              {enabledFeatures["forgot-password-enabled"] && (
                <a
                  href="/login/forgot-password"
                  style={{ display: "block", flexGrow: 1, textAlign: "end" }}
                >
                  {t(K.FORGET_PASSWORD)}
                </a>
              )}
            </div>
          </Form.Item>
        </Form>
      );
    };
    const changeLoginMethod = (event: string) => {
      this.setState({ currentLoginMethod: event });
    };
    return (
      <>
        <div className={styles.loginWrapper}>
          <div className={styles.loginHeader}>
            <div className={styles.logoBar}>
              <Link to="/">
                {brand.auth_logo_url ? (
                  <img
                    src={brand.auth_logo_url}
                    style={{ height: 32, verticalAlign: "middle" }}
                  />
                ) : (
                  <Logo height={32} style={{ verticalAlign: "middle" }} />
                )}
              </Link>
            </div>
          </div>
          <div className={styles.loginImg}>
            <img src={loginPng} style={{ height: this.state.imageHeight }} />
          </div>
          <div className={styles.loginForm}>
            {this.state.wxQRCodeLogin ? (
              <Tabs defaultActiveKey="code">
                <Tabs.TabPane
                  tab={t(K.WX_LOGIN_TITLE)}
                  key="code"
                  className={styles.wxQRCodeLoginTab}
                >
                  <Card bordered={false} className={styles.wxQRCodeLoginCard}>
                    <div id="wxQRCode"></div>
                  </Card>
                </Tabs.TabPane>
                <Tabs.TabPane tab={t(K.LOGIN_TITLE)} key="normal">
                  <Card title={t(K.LOGIN_TITLE)} bordered={false}>
                    {renderLoginForm()}
                  </Card>
                </Tabs.TabPane>
              </Tabs>
            ) : this.loginMethods.length === 1 ? (
              <Card
                title={
                  (this.loginMethodsMap as any)[this.state.currentLoginMethod]
                }
                bordered={false}
              >
                {renderLoginForm()}
              </Card>
            ) : (
              <Card>
                <Tabs
                  onChange={changeLoginMethod}
                  activeKey={this.state.currentLoginMethod}
                >
                  {this.loginMethods.map((item: string) => {
                    return (
                      <Tabs.TabPane
                        tab={(this.loginMethodsMap as any)[item]}
                        key={item}
                      >
                        {renderLoginForm()}
                      </Tabs.TabPane>
                    );
                  })}
                </Tabs>
              </Card>
            )}
            {this.state.MFALogin && (
              <MFALogin
                onCancel={this.handleCancel}
                dataSource={this.state.mfaInfo}
                redirect={this.redirect}
              />
            )}
          </div>
        </div>
      </>
    );
  }
Example #16
Source File: index.tsx    From react_admin with MIT License 4 votes vote down vote up
Login: React.FC<Iprops> = (props) => {
  const username = useInput("");
  const password = useInput("");
  const code = useInput("");
  const inputRef = useRef<any>(null);
  const [loading, setLoading] = useState(false);

  /**
   * 判断是否登录过 && 获取焦点
   */
  useEffect(() => {
    const userinfo = localStorage.getItem("userinfo")
      ? JSON.parse(localStorage.getItem("userinfo") as string)
      : null;
    if (userinfo) {
      props.history.replace("/home");
    } else {
      inputRef.current.focus();
    }
  }, []);

  /**
   * @function
   * 登录校验 发出请求
   */
  const handleSubmit = async () => {
    const _loginName = username.val.trim();
    const _password = password.val.trim();
    const _code = code.val.trim();

    try {
      if (!_loginName) throw new Error("用户名不能为空");
      if (!_password) throw new Error("密码不能为空");
      if (!_code) throw new Error("验证码不能为空");
      if (_code !== captcha) throw new Error("验证码错误");

      setLoading(true);
      const data = (await getUserLoginData({
        data: { _loginName, _password },
        url: API.getLogin,
      })) as Ilogin;
      setLoading(false);
      // 登录成功
      if (_loginName === data.username && _password === data.password) {
        localStorage.setItem(
          "userinfo",
          JSON.stringify({ _loginName, _password })
        );
        await props.setUserInfoMy({ _loginName, _password });
        props.history.replace("/home");
      } else {
        throw new Error("用户名密码错误");
      }
    } catch (err) {
      message.error(err.message);
      return;
    }
  };
  const reloadCaptcha = useCallback((e) => {
    captcha = getRandom();
    let url = API.getCaptcha + captcha;
    e.target.src = url;
  }, []);

  return (
    <section className="login-page">
      <a
        rel="noopener noreferrer"
        className="login-right"
        href="https://github.com/2662419405"
        target="_blank"
      >
        <img
          src="https://github.blog/wp-content/uploads/2008/12/forkme_right_darkblue_121621.png?resize=149%2C149"
          alt="github"
        />
      </a>
      <div className="wrap">
        <div>
          <div className="logo-wrap">
            <img
              alt="logo"
              className="logo"
              src={require("../../assets/img/sh.png")}
            />
            <em>TS + Hooks</em>
          </div>
          <Input.Group>
            <Input
              ref={inputRef}
              {...username}
              onPressEnter={handleSubmit}
              prefix={<UserOutlined />}
              maxLength={32}
              autoComplete="off"
              placeholder="username/admin"
            />
            <Input
              {...password}
              prefix={<LockOutlined />}
              onPressEnter={handleSubmit}
              type="password"
              maxLength={32}
              autoComplete="off"
              placeholder="password/123456"
            />
            <Input
              {...code}
              onKeyDown={(e) => {
                if (e.keyCode === 13) handleSubmit();
              }}
              prefix={<PictureOutlined />}
              onPressEnter={handleSubmit}
              maxLength={4}
              autoComplete="off"
              placeholder="请输入验证码"
              suffix={
                <img
                  className="captcha"
                  src={API.getCaptcha + captcha}
                  onClick={reloadCaptcha}
                  alt="code"
                />
              }
            />
          </Input.Group>
          <Button
            size="large"
            className="weitiao-btn"
            block={true}
            type="primary"
            onClick={handleSubmit}
            loading={loading}
          >
            {loading ? "正在登录" : "登录"}
          </Button>
          <div className="other-login">
            <span className="txt">其他登录方式</span>
            <GithubOutlined className="github-icon" />
            <div className="href-right">
              <Tooltip
                placement="bottom"
                title="账号为admin,密码为123456,推荐使用第三方github进行登录"
              >
                <span className="text-right">注册账号</span>
              </Tooltip>
            </div>
          </div>
        </div>
      </div>
      <Footer />
    </section>
  );
}
Example #17
Source File: FeatureFlag.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function FeatureFlag(): JSX.Element {
    const [form] = Form.useForm()
    const {
        featureFlag,
        featureFlagId,
        multivariateEnabled,
        variants,
        nonEmptyVariants,
        areVariantRolloutsValid,
        variantRolloutSum,
        groupTypes,
        aggregationTargetName,
        taxonomicGroupTypes,
    } = useValues(featureFlagLogic)
    const {
        addConditionSet,
        updateConditionSet,
        removeConditionSet,
        duplicateConditionSet,
        saveFeatureFlag,
        deleteFeatureFlag,
        setMultivariateEnabled,
        addVariant,
        updateVariant,
        removeVariant,
        distributeVariantsEqually,
        setFeatureFlag,
        setAggregationGroupTypeIndex,
    } = useActions(featureFlagLogic)
    const { showGroupsOptions, aggregationLabel } = useValues(groupsModel)
    const { hasAvailableFeature, upgradeLink } = useValues(userLogic)

    // whether the key for an existing flag is being changed
    const [hasKeyChanged, setHasKeyChanged] = useState(false)
    // whether to warn the user that their variants will be lost
    const [showVariantDiscardWarning, setShowVariantDiscardWarning] = useState(false)

    useEffect(() => {
        form.setFieldsValue({ ...featureFlag })
    }, [featureFlag])

    // :KLUDGE: Match by select only allows Select.Option as children, so render groups option directly rather than as a child
    const matchByGroupsIntroductionOption = GroupsIntroductionOption({ value: -2 })

    return (
        <div className="feature-flag">
            {featureFlag ? (
                <Form
                    layout="vertical"
                    form={form}
                    initialValues={{ name: featureFlag.name, key: featureFlag.key, active: featureFlag.active }}
                    onValuesChange={(newValues) => {
                        if (featureFlagId !== 'new' && newValues.key) {
                            setHasKeyChanged(newValues.key !== featureFlag.key)
                        }
                        setFeatureFlag({ ...featureFlag, ...newValues })
                    }}
                    onFinish={(values) =>
                        saveFeatureFlag({
                            ...featureFlag,
                            ...values,
                            filters: featureFlag.filters,
                        })
                    }
                    requiredMark={false}
                    scrollToFirstError
                >
                    <PageHeader
                        title="Feature Flag"
                        buttons={
                            <div style={{ display: 'flex' }}>
                                <Form.Item className="enabled-switch">
                                    <Form.Item
                                        shouldUpdate={(prevValues, currentValues) =>
                                            prevValues.active !== currentValues.active
                                        }
                                        style={{ marginBottom: 0, marginRight: 6 }}
                                    >
                                        {({ getFieldValue }) => {
                                            return (
                                                <span className="ant-form-item-label" style={{ lineHeight: '1.5rem' }}>
                                                    {getFieldValue('active') ? (
                                                        <span className="text-success">Enabled</span>
                                                    ) : (
                                                        <span className="text-danger">Disabled</span>
                                                    )}
                                                </span>
                                            )
                                        }}
                                    </Form.Item>
                                    <Form.Item name="active" noStyle valuePropName="checked">
                                        <Switch />
                                    </Form.Item>
                                </Form.Item>
                                {featureFlagId !== 'new' && (
                                    <Button
                                        data-attr="delete-flag"
                                        danger
                                        icon={<DeleteOutlined />}
                                        onClick={() => {
                                            deleteFeatureFlag(featureFlag)
                                        }}
                                        style={{ marginRight: 16 }}
                                    >
                                        Delete
                                    </Button>
                                )}
                                <Button
                                    icon={<SaveOutlined />}
                                    type="primary"
                                    data-attr="feature-flag-submit"
                                    htmlType="submit"
                                >
                                    Save changes
                                </Button>
                            </div>
                        }
                    />
                    <h3 className="l3">General configuration</h3>
                    <div className="text-muted mb">
                        General settings for your feature flag and integration instructions.
                    </div>
                    <Row gutter={16} style={{ marginBottom: 32 }}>
                        <Col span={12}>
                            <Form.Item
                                name="key"
                                label="Key (must be unique)"
                                rules={[
                                    { required: true, message: 'You need to set a key.' },
                                    {
                                        pattern: /^([A-z]|[a-z]|[0-9]|-|_)+$/,
                                        message: 'Only letters, numbers, hyphens (-) & underscores (_) are allowed.',
                                    },
                                ]}
                                validateStatus={hasKeyChanged ? 'warning' : undefined}
                                help={
                                    hasKeyChanged ? (
                                        <small>
                                            <b>Warning! </b>Changing this key will
                                            <a
                                                href={`https://posthog.com/docs/features/feature-flags${UTM_TAGS}#feature-flag-persistence`}
                                                target="_blank"
                                                rel="noopener"
                                            >
                                                {' '}
                                                affect the persistence of your flag <IconOpenInNew />
                                            </a>
                                        </small>
                                    ) : undefined
                                }
                            >
                                <Input
                                    data-attr="feature-flag-key"
                                    className="ph-ignore-input"
                                    autoFocus
                                    placeholder="examples: new-landing-page, betaFeature, ab_test_1"
                                    autoComplete="off"
                                    autoCapitalize="off"
                                    autoCorrect="off"
                                    spellCheck={false}
                                />
                            </Form.Item>

                            <Form.Item name="name" label="Description">
                                <Input.TextArea
                                    className="ph-ignore-input"
                                    data-attr="feature-flag-description"
                                    placeholder="Adding a helpful description can ensure others know what this feature is for."
                                />
                            </Form.Item>
                        </Col>
                        <Col span={12} style={{ paddingTop: 31 }}>
                            <Collapse>
                                <Collapse.Panel
                                    header={
                                        <div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
                                            <IconJavascript style={{ marginRight: 6 }} /> Javascript integration
                                            instructions
                                        </div>
                                    }
                                    key="js"
                                >
                                    <Form.Item
                                        shouldUpdate={(prevValues, currentValues) =>
                                            prevValues.key !== currentValues.key
                                        }
                                    >
                                        {({ getFieldValue }) => <JSSnippet flagKey={getFieldValue('key')} />}
                                    </Form.Item>
                                </Collapse.Panel>
                                <Collapse.Panel
                                    header={
                                        <div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
                                            <IconPython style={{ marginRight: 6 }} /> Python integration instructions
                                        </div>
                                    }
                                    key="python"
                                >
                                    <Form.Item
                                        shouldUpdate={(prevValues, currentValues) =>
                                            prevValues.key !== currentValues.key
                                        }
                                    >
                                        {({ getFieldValue }) => <PythonSnippet flagKey={getFieldValue('key')} />}
                                    </Form.Item>
                                </Collapse.Panel>
                                <Collapse.Panel
                                    header={
                                        <div style={{ display: 'flex', fontWeight: 'bold', alignItems: 'center' }}>
                                            <ApiFilled style={{ marginRight: 6 }} /> API integration instructions
                                        </div>
                                    }
                                    key="api"
                                >
                                    <Form.Item
                                        shouldUpdate={(prevValues, currentValues) =>
                                            prevValues.key !== currentValues.key
                                        }
                                    >
                                        <APISnippet />
                                    </Form.Item>
                                </Collapse.Panel>
                            </Collapse>
                        </Col>
                    </Row>

                    <div className="mb-2">
                        <h3 className="l3">Served value</h3>
                        <div className="mb-05">
                            <Popconfirm
                                placement="top"
                                title="Change value type? The variants below will be lost."
                                visible={showVariantDiscardWarning}
                                onConfirm={() => {
                                    setMultivariateEnabled(false)
                                    setShowVariantDiscardWarning(false)
                                }}
                                onCancel={() => setShowVariantDiscardWarning(false)}
                                okText="OK"
                                cancelText="Cancel"
                            >
                                <Radio.Group
                                    options={[
                                        {
                                            label: 'Boolean value (A/B test)',
                                            value: false,
                                        },
                                        {
                                            label: (
                                                <Tooltip
                                                    title={
                                                        hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS)
                                                            ? ''
                                                            : 'This feature is not available on your current plan.'
                                                    }
                                                >
                                                    <div>
                                                        {!hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS) && (
                                                            <Link to={upgradeLink} target="_blank">
                                                                <LockOutlined
                                                                    style={{ marginRight: 4, color: 'var(--warning)' }}
                                                                />
                                                            </Link>
                                                        )}
                                                        String value (Multivariate test){' '}
                                                        <LemonTag type="warning">Beta</LemonTag>
                                                    </div>
                                                </Tooltip>
                                            ),
                                            value: true,
                                            disabled: !hasAvailableFeature(AvailableFeature.MULTIVARIATE_FLAGS),
                                        },
                                    ]}
                                    onChange={(e) => {
                                        const { value } = e.target
                                        if (value === false && nonEmptyVariants.length) {
                                            setShowVariantDiscardWarning(true)
                                        } else {
                                            setMultivariateEnabled(value)
                                            focusVariantKeyField(0)
                                        }
                                    }}
                                    value={multivariateEnabled}
                                    optionType="button"
                                />
                            </Popconfirm>
                        </div>
                        <div className="text-muted mb">
                            {capitalizeFirstLetter(aggregationTargetName)} will be served{' '}
                            {multivariateEnabled ? (
                                <>
                                    <strong>a variant key</strong> according to the below distribution
                                </>
                            ) : (
                                <strong>
                                    <code>true</code>
                                </strong>
                            )}{' '}
                            if they match one or more release condition groups.
                        </div>
                        {multivariateEnabled && (
                            <div className="variant-form-list">
                                <Row gutter={8} className="label-row">
                                    <Col span={7}>Variant key</Col>
                                    <Col span={7}>Description</Col>
                                    <Col span={9}>
                                        <span>Rollout percentage</span>
                                        <Button
                                            type="link"
                                            onClick={distributeVariantsEqually}
                                            icon={<MergeCellsOutlined />}
                                            style={{ padding: '0 0 0 0.5em' }}
                                            title="Distribute variants equally"
                                        >
                                            Distribute
                                        </Button>
                                    </Col>
                                </Row>
                                {variants.map(({ rollout_percentage }, index) => (
                                    <Form
                                        key={index}
                                        onValuesChange={(changedValues) => updateVariant(index, changedValues)}
                                        initialValues={variants[index]}
                                        validateTrigger={['onChange', 'onBlur']}
                                    >
                                        <Row gutter={8}>
                                            <Col span={7}>
                                                <Form.Item
                                                    name="key"
                                                    rules={[
                                                        { required: true, message: 'Key should not be empty.' },
                                                        {
                                                            pattern: /^([A-z]|[a-z]|[0-9]|-|_)+$/,
                                                            message:
                                                                'Only letters, numbers, hyphens (-) & underscores (_) are allowed.',
                                                        },
                                                    ]}
                                                >
                                                    <Input
                                                        data-attr="feature-flag-variant-key"
                                                        data-key-index={index.toString()}
                                                        className="ph-ignore-input"
                                                        placeholder={`example-variant-${index + 1}`}
                                                        autoComplete="off"
                                                        autoCapitalize="off"
                                                        autoCorrect="off"
                                                        spellCheck={false}
                                                    />
                                                </Form.Item>
                                            </Col>
                                            <Col span={7}>
                                                <Form.Item name="name">
                                                    <Input
                                                        data-attr="feature-flag-variant-name"
                                                        className="ph-ignore-input"
                                                        placeholder="Description"
                                                    />
                                                </Form.Item>
                                            </Col>
                                            <Col span={7}>
                                                <Slider
                                                    tooltipPlacement="top"
                                                    value={rollout_percentage}
                                                    onChange={(value: number) =>
                                                        updateVariant(index, { rollout_percentage: value })
                                                    }
                                                />
                                            </Col>
                                            <Col span={2}>
                                                <InputNumber
                                                    min={0}
                                                    max={100}
                                                    value={rollout_percentage}
                                                    onChange={(value) => {
                                                        if (value !== null && value !== undefined) {
                                                            const valueInt = parseInt(value.toString())
                                                            if (!isNaN(valueInt)) {
                                                                updateVariant(index, {
                                                                    rollout_percentage: valueInt,
                                                                })
                                                            }
                                                        }
                                                    }}
                                                    style={{
                                                        width: '100%',
                                                        borderColor: areVariantRolloutsValid
                                                            ? undefined
                                                            : 'var(--danger)',
                                                    }}
                                                />
                                            </Col>
                                            {variants.length > 1 && (
                                                <Col span={1}>
                                                    <Tooltip title="Delete this variant" placement="bottomLeft">
                                                        <Button
                                                            type="link"
                                                            icon={<DeleteOutlined />}
                                                            onClick={() => removeVariant(index)}
                                                            style={{ color: 'var(--danger)' }}
                                                        />
                                                    </Tooltip>
                                                </Col>
                                            )}
                                        </Row>
                                    </Form>
                                ))}
                                {variants.length > 0 && !areVariantRolloutsValid && (
                                    <p className="text-danger">
                                        Percentage rollouts for variants must sum to 100 (currently {variantRolloutSum}
                                        ).
                                    </p>
                                )}
                                <Button
                                    type="dashed"
                                    block
                                    icon={<PlusOutlined />}
                                    onClick={() => {
                                        const newIndex = variants.length
                                        addVariant()
                                        focusVariantKeyField(newIndex)
                                    }}
                                    style={{ marginBottom: 16 }}
                                >
                                    Add Variant
                                </Button>
                            </div>
                        )}
                    </div>

                    <div className="feature-flag-form-row">
                        <div>
                            <h3 className="l3">Release conditions</h3>
                            <div className="text-muted mb">
                                Specify the {aggregationTargetName} to which you want to release this flag. Note that
                                condition sets are rolled out independently of each other.
                            </div>
                        </div>
                        {showGroupsOptions && (
                            <div className="centered">
                                Match by
                                <Select
                                    value={
                                        featureFlag.filters.aggregation_group_type_index != null
                                            ? featureFlag.filters.aggregation_group_type_index
                                            : -1
                                    }
                                    onChange={(value) => {
                                        const groupTypeIndex = value !== -1 ? value : null
                                        setAggregationGroupTypeIndex(groupTypeIndex)
                                    }}
                                    style={{ marginLeft: 8 }}
                                    data-attr="feature-flag-aggregation-filter"
                                    dropdownMatchSelectWidth={false}
                                    dropdownAlign={{
                                        // Align this dropdown by the right-hand-side of button
                                        points: ['tr', 'br'],
                                    }}
                                >
                                    <Select.Option key={-1} value={-1}>
                                        Users
                                    </Select.Option>
                                    {groupTypes.map((groupType) => (
                                        <Select.Option
                                            key={groupType.group_type_index}
                                            value={groupType.group_type_index}
                                        >
                                            {capitalizeFirstLetter(aggregationLabel(groupType.group_type_index).plural)}
                                        </Select.Option>
                                    ))}
                                    {matchByGroupsIntroductionOption}
                                </Select>
                            </div>
                        )}
                    </div>
                    <Row gutter={16}>
                        {featureFlag.filters.groups.map((group, index) => (
                            <Col span={24} md={24} key={`${index}-${featureFlag.filters.groups.length}`}>
                                {index > 0 && (
                                    <div style={{ display: 'flex', marginLeft: 16 }}>
                                        <div className="stateful-badge or-light-grey mb">OR</div>
                                    </div>
                                )}
                                <Card style={{ marginBottom: 16 }}>
                                    <div className="feature-flag-form-row" style={{ height: 24 }}>
                                        <div>
                                            <span className="simple-tag tag-light-blue" style={{ marginRight: 8 }}>
                                                Set {index + 1}
                                            </span>
                                            {group.properties?.length ? (
                                                <>
                                                    Matching <b>{aggregationTargetName}</b> with filters
                                                </>
                                            ) : (
                                                <>
                                                    Condition set will match <b>all {aggregationTargetName}</b>
                                                </>
                                            )}
                                        </div>
                                        <div>
                                            <Tooltip title="Duplicate this condition set" placement="bottomLeft">
                                                <Button
                                                    type="link"
                                                    icon={<CopyOutlined />}
                                                    style={{ width: 24, height: 24 }}
                                                    onClick={() => duplicateConditionSet(index)}
                                                />
                                            </Tooltip>
                                            {featureFlag.filters.groups.length > 1 && (
                                                <Tooltip title="Delete this condition set" placement="bottomLeft">
                                                    <Button
                                                        type="link"
                                                        icon={<DeleteOutlined />}
                                                        style={{ width: 24, height: 24 }}
                                                        onClick={() => removeConditionSet(index)}
                                                    />
                                                </Tooltip>
                                            )}
                                        </div>
                                    </div>

                                    <LemonSpacer large />
                                    <PropertyFilters
                                        style={{ marginLeft: 15 }}
                                        pageKey={`feature-flag-${featureFlag.id}-${index}-${
                                            featureFlag.filters.groups.length
                                        }-${featureFlag.filters.aggregation_group_type_index ?? ''}`}
                                        propertyFilters={group?.properties}
                                        onChange={(properties) => updateConditionSet(index, undefined, properties)}
                                        taxonomicGroupTypes={taxonomicGroupTypes}
                                        showConditionBadge
                                        greyBadges
                                    />
                                    <LemonSpacer large />

                                    <div className="feature-flag-form-row">
                                        <div className="centered">
                                            Roll out to{' '}
                                            <InputNumber
                                                style={{ width: 100, marginLeft: 8, marginRight: 8 }}
                                                onChange={(value): void => {
                                                    updateConditionSet(index, value as number)
                                                }}
                                                value={
                                                    group.rollout_percentage != null ? group.rollout_percentage : 100
                                                }
                                                min={0}
                                                max={100}
                                                addonAfter="%"
                                            />{' '}
                                            of <b>{aggregationTargetName}</b> in this set
                                        </div>
                                    </div>
                                </Card>
                            </Col>
                        ))}
                    </Row>
                    <Card size="small" style={{ marginBottom: 16 }}>
                        <Button type="link" onClick={addConditionSet} style={{ marginLeft: 5 }}>
                            <PlusOutlined style={{ marginRight: 15 }} /> Add condition set
                        </Button>
                    </Card>
                    <Form.Item className="text-right">
                        <Button
                            icon={<SaveOutlined />}
                            htmlType="submit"
                            type="primary"
                            data-attr="feature-flag-submit-bottom"
                        >
                            Save changes
                        </Button>
                    </Form.Item>
                </Form>
            ) : (
                // TODO: This should be skeleton loaders
                <SceneLoading />
            )}
        </div>
    )
}
Example #18
Source File: TableConfig.tsx    From posthog-foss with MIT License 4 votes vote down vote up
function ColumnConfigurator({ immutableColumns, defaultColumns, availableColumns }: TableConfigProps): JSX.Element {
    // the virtualised list doesn't support gaps between items in the list
    // setting the container to be larger than we need
    // and adding a container with a smaller height to each row item
    // allows the new row item to set a margin around itself
    const rowContainerHeight = 36
    const rowItemHeight = 32

    const { selectedColumns, modalVisible } = useValues(tableConfigLogic)
    const { hideModal } = useActions(tableConfigLogic)

    const logic = columnConfiguratorLogic({
        availableColumns,
        selectedColumns: selectedColumns === 'DEFAULT' ? defaultColumns : selectedColumns,
    })
    const { selectColumn, unselectColumn, resetColumns, save, setColumnFilter } = useActions(logic)
    const { visibleColumns, hiddenColumns, scrollIndex, columnFilter, filteredVisibleColumns, filteredHiddenColumns } =
        useValues(logic)

    function AvailableColumn({ index, style, key }: ListRowProps): JSX.Element {
        return (
            <div style={style} key={key} onClick={() => selectColumn(filteredHiddenColumns[index])}>
                <div className="column-display-item" style={{ height: `${rowItemHeight}px` }}>
                    <PropertyKeyInfo value={filteredHiddenColumns[index]} />
                    <div className="text-right" style={{ flex: 1 }}>
                        <Tooltip title="Add">
                            <PlusOutlined style={{ color: 'var(--success)' }} />
                        </Tooltip>
                    </div>
                </div>
            </div>
        )
    }

    function SelectedColumn({ index, style, key }: ListRowProps): JSX.Element {
        const disabled = immutableColumns?.includes(filteredVisibleColumns[index])

        return (
            <div style={style} key={key} onClick={() => !disabled && unselectColumn(filteredVisibleColumns[index])}>
                <div
                    className={clsx(['column-display-item', { selected: !disabled, disabled: disabled }])}
                    style={{ height: `${rowItemHeight}px` }}
                >
                    <PropertyKeyInfo value={filteredVisibleColumns[index]} />
                    <div className="text-right" style={{ flex: 1 }}>
                        <Tooltip title={disabled ? 'Reserved' : 'Remove'}>
                            {disabled ? <LockOutlined /> : <CloseOutlined style={{ color: 'var(--danger)' }} />}
                        </Tooltip>
                    </div>
                </div>
            </div>
        )
    }

    return (
        <Modal
            centered
            visible={modalVisible}
            title="Customize columns"
            onOk={save}
            width={700}
            bodyStyle={{ padding: '16px 16px 0 16px' }}
            className="column-configurator-modal"
            okButtonProps={{
                // @ts-ignore
                'data-attr': 'items-selector-confirm',
            }}
            okText="Save"
            onCancel={hideModal}
            footer={
                <Row>
                    <Space style={{ flexGrow: 1 }} align="start">
                        <Button className="text-blue" onClick={() => resetColumns(defaultColumns)}>
                            Reset to default
                        </Button>
                    </Space>
                    <Space>
                        <Button className="text-blue" type="text" onClick={hideModal}>
                            Cancel
                        </Button>
                        <Button type="primary" onClick={save}>
                            Save
                        </Button>
                    </Space>
                </Row>
            }
        >
            <Search
                allowClear
                autoFocus
                placeholder="Search"
                type="search"
                value={columnFilter}
                onChange={(e) => setColumnFilter(e.target.value)}
            />
            <Row gutter={16} className="mt">
                <Col xs={24} sm={12}>
                    <h3 className="l3">Hidden columns ({hiddenColumns.length})</h3>
                    <div style={{ height: 320 }}>
                        <AutoSizer>
                            {({ height, width }: { height: number; width: number }) => {
                                return (
                                    <VirtualizedList
                                        height={height}
                                        rowCount={filteredHiddenColumns.length}
                                        rowRenderer={AvailableColumn}
                                        rowHeight={rowContainerHeight}
                                        width={width}
                                    />
                                )
                            }}
                        </AutoSizer>
                    </div>
                </Col>
                <Col xs={24} sm={12}>
                    <h3 className="l3">Visible columns ({visibleColumns.length})</h3>
                    <div style={{ height: 320 }}>
                        <AutoSizer>
                            {({ height, width }: { height: number; width: number }) => {
                                return (
                                    <VirtualizedList
                                        height={height}
                                        rowCount={filteredVisibleColumns.length}
                                        rowRenderer={SelectedColumn}
                                        rowHeight={rowContainerHeight}
                                        width={width}
                                        scrollToIndex={scrollIndex}
                                    />
                                )
                            }}
                        </AutoSizer>
                    </div>
                </Col>
            </Row>
        </Modal>
    )
}
Example #19
Source File: EditableField.tsx    From posthog-foss with MIT License 4 votes vote down vote up
export function EditableField({
    name,
    value,
    onChange,
    className,
    dataAttr,
    placeholder,
    locked,
    multiline,
}: EditableFieldProps): JSX.Element {
    const [isEditing, setIsEditing] = useState(false)
    const [editedValue, setEditedValue] = useState(value)

    useEffect(() => {
        setEditedValue(value)
    }, [value])

    return (
        <div
            className={`editable-field${className ? ` ${className}` : ''} ${isEditing ? 'edit-mode' : 'view-mode'}`}
            data-attr={dataAttr}
        >
            {isEditing ? (
                <div className="edit-container ant-input-affix-wrapper ant-input-affix-wrapper-lg editable-textarea-wrapper">
                    <Input.TextArea
                        autoFocus
                        placeholder={placeholder}
                        value={multiline ? editedValue : editedValue.split('\n').join('')}
                        onChange={(e) => setEditedValue(e.target.value)}
                        onKeyDown={(e) => {
                            if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
                                onChange(editedValue)
                                setIsEditing(false)
                            }
                        }}
                        autoSize={{ minRows: 1, maxRows: 5 }}
                    />

                    <Button className="btn-cancel" size="small" onClick={() => setIsEditing(false)}>
                        Cancel
                    </Button>
                    <Button
                        className="ml-025"
                        type="primary"
                        size="small"
                        onClick={() => {
                            onChange(editedValue)
                            setIsEditing(false)
                        }}
                    >
                        Done
                    </Button>
                </div>
            ) : (
                <div className="view-container">
                    <span className="field">{value || <i>{placeholder}</i>}</span>
                    {!locked ? (
                        <Button
                            type="link"
                            onClick={() => {
                                setEditedValue(value)
                                setIsEditing(true)
                            }}
                            className="btn-edit"
                            data-attr={`edit-prop-${name}`}
                            title={`Edit ${name}`}
                        >
                            <EditOutlined />
                        </Button>
                    ) : (
                        <Tooltip
                            title="This field is part of PostHog's team-oriented feature set and requires a premium plan. Check PostHog pricing."
                            isDefaultTooltip
                        >
                            <LockOutlined style={{ marginLeft: 6, color: 'var(--text-muted)' }} />
                        </Tooltip>
                    )}
                </div>
            )}
        </div>
    )
}
Example #20
Source File: Login.tsx    From jmix-frontend with Apache License 2.0 4 votes vote down vote up
Login = observer(() => {
  const intl = useIntl();

  const mainStore = useMainStore();

  const [login, setLogin] = useState("");
  const [password, setPassword] = useState("");
  const [performingLoginRequest, setPerformingLoginRequest] = useState(false);

  const changeLogin = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => setLogin(e.target.value),
    [setLogin]
  );
  const changePassword = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => setPassword(e.target.value),
    [setPassword]
  );

  const doLogin = useCallback(() => {
    setPerformingLoginRequest(true);
    mainStore
      .login(login, password)
      .then(
        action(() => {
          setPerformingLoginRequest(false);
        })
      )
      .catch(
        action((error: JmixServerError) => {
          setPerformingLoginRequest(false);

          const loginMessageErrorIntlId = loginMapJmixRestErrorToIntlId(error);
          message.error(intl.formatMessage({ id: loginMessageErrorIntlId }));
        })
      );
  }, [setPerformingLoginRequest, mainStore, intl, login, password]);

  return (
    <Card className={styles.loginForm}>
      <JmixDarkIcon className={styles.logo} />

      <div className={styles.title}>scr-jmix</div>

      <Form layout="vertical" onFinish={doLogin}>
        <Form.Item>
          <Input
            id="input_login"
            placeholder={intl.formatMessage({ id: "login.placeholder.login" })}
            onChange={changeLogin}
            value={login}
            prefix={<UserOutlined style={{ margin: "0 11px 0 0" }} />}
            size="large"
          />
        </Form.Item>
        <Form.Item>
          <Input
            id="input_password"
            placeholder={intl.formatMessage({
              id: "login.placeholder.password"
            })}
            onChange={changePassword}
            value={password}
            type="password"
            prefix={<LockOutlined style={{ margin: "0 11px 0 0" }} />}
            size="large"
          />
        </Form.Item>
        <Form.Item>
          <div className={styles.languageSwitcherContainer}>
            <LanguageSwitcher />
          </div>
        </Form.Item>
        <Form.Item>
          <Button
            type="primary"
            htmlType="submit"
            size="large"
            block={true}
            loading={performingLoginRequest}
          >
            <FormattedMessage id="login.loginBtn" />
          </Button>
        </Form.Item>
      </Form>
    </Card>
  );
})
Example #21
Source File: index.tsx    From shippo with MIT License 4 votes vote down vote up
Page_passport = () => {
  const history = useNavigate()

  const handleSmsSend = (phone: string) => {
    console.log('handleSmsSend', { phone })
    if (!checkPhone(phone)) {
      return message.info('手机号格式错误')
    }
    services.captcha.send({ phone })
    message.success('验证码已经发送')
  }

  const [form] = Form.useForm<{ phone: string; captcha: string }>()

  const onFinish = async (values: { phone: string; captcha: string }) => {
    console.log('Received values of form: ', values)
    const { phone, captcha: code } = values

    if (!checkPhone(phone)) {
      return message.info('手机号格式错误')
    }
    if (!checkSmsCode(code)) {
      return message.info('短信验证码格式错误')
    }
    const { data } = await services.user.login({
      phone,
      code,
    })
    window.localStorage.setItem('__PASSPORT', data.resource.passport)
    history('/')
  }

  return (
    <Layout>
      <Header
        style={{
          background: 'transparent',
          textAlign: 'center',
          height: '200px',
          lineHeight: '200px',
        }}
      >
        <span
          style={{
            color: 'rgba(0,0,0,.85)',
            fontWeight: 600,
            fontSize: '33px',
          }}
        >
          Shippo
        </span>
      </Header>
      <Content>
        <div style={{ width: '328px', margin: '0 auto' }}>
          <Form form={form} name="register" onFinish={onFinish} scrollToFirstError>
            <Form.Item name="phone" rules={[{ required: true, message: '请输入你的手机号!' }]}>
              <Input
                prefix={<LockOutlined className="site-form-item-icon" />}
                placeholder="请输入你的手机号!"
                style={{ width: '100%' }}
                allowClear
                size="large"
              />
            </Form.Item>

            <Form.Item>
              <div
                style={{
                  display: 'flex',
                  alignItems: 'center',
                }}
              >
                <Form.Item
                  name="captcha"
                  noStyle
                  rules={[{ required: true, message: '请输入验证码!' }]}
                >
                  <Input
                    prefix={<UserOutlined className="site-form-item-icon" />}
                    placeholder="请输入验证码!"
                    style={{
                      flex: 1,
                      marginRight: 8,
                    }}
                    size="large"
                  />
                </Form.Item>
                <Button
                  style={{
                    display: 'block',
                  }}
                  onClick={() => handleSmsSend(form.getFieldValue('phone'))}
                  size="large"
                >
                  获取验证码
                </Button>
              </div>
            </Form.Item>

            <Form.Item>
              <Button type="primary" htmlType="submit" style={{ width: '100%' }} size="large">
                登录
              </Button>
            </Form.Item>
          </Form>
        </div>
      </Content>
      <Footer
        style={{
          textAlign: 'center',
          marginBottom: '25px',
          color: 'rgba(0,0,0,.45)',
          fontSize: '14px',
        }}
      >
        <CopyrightOutlined /> 2021 Shippo
      </Footer>
    </Layout>
  )
}
Example #22
Source File: index.tsx    From shippo with MIT License 4 votes vote down vote up
Page_passport = () => {
  const history = useNavigate()

  const handleSmsSend = (phone: string) => {
    console.log('handleSmsSend', { phone })
    if (!checkPhone(phone)) {
      return message.info('手机号格式错误')
    }
    services.captcha.send({ phone })
    message.success('验证码已经发送')
  }

  const [form] = Form.useForm<{ phone: string; captcha: string }>()

  const onFinish = async (values: { phone: string; captcha: string }) => {
    console.log('Received values of form: ', values)
    const { phone, captcha: code } = values

    if (!checkPhone(phone)) {
      return message.info('手机号格式错误')
    }
    if (!checkSmsCode(code)) {
      return message.info('短信验证码格式错误')
    }
    const { data } = await services.user.login({
      phone,
      code,
    })
    window.localStorage.setItem('__PASSPORT', data.resource.passport)
    history('/')
  }

  return (
    <Layout>
      <Header
        style={{
          background: 'transparent',
          textAlign: 'center',
          height: '200px',
          lineHeight: '200px',
        }}
      >
        <span
          style={{
            color: 'rgba(0,0,0,.85)',
            fontWeight: 600,
            fontSize: '33px',
          }}
        >
          Shippo Admin
        </span>
      </Header>
      <Content>
        <div style={{ width: '328px', margin: '0 auto' }}>
          <Form form={form} name="register" onFinish={onFinish} scrollToFirstError>
            <Form.Item name="phone" rules={[{ required: true, message: '请输入你的手机号!' }]}>
              <Input
                prefix={<LockOutlined className="site-form-item-icon" />}
                placeholder="请输入你的手机号!"
                style={{ width: '100%' }}
                allowClear
                size="large"
              />
            </Form.Item>

            <Form.Item>
              <div
                style={{
                  display: 'flex',
                  alignItems: 'center',
                }}
              >
                <Form.Item
                  name="captcha"
                  noStyle
                  rules={[{ required: true, message: '请输入验证码!' }]}
                >
                  <Input
                    prefix={<UserOutlined className="site-form-item-icon" />}
                    placeholder="请输入验证码!"
                    style={{
                      flex: 1,
                      marginRight: 8,
                    }}
                    size="large"
                  />
                </Form.Item>
                <Button
                  style={{
                    display: 'block',
                  }}
                  onClick={() => handleSmsSend(form.getFieldValue('phone'))}
                  size="large"
                >
                  获取验证码
                </Button>
              </div>
            </Form.Item>

            <Form.Item>
              <Button type="primary" htmlType="submit" style={{ width: '100%' }} size="large">
                登录
              </Button>
            </Form.Item>
          </Form>
        </div>
      </Content>
      <Footer
        style={{
          textAlign: 'center',
          marginBottom: '25px',
          color: 'rgba(0,0,0,.45)',
          fontSize: '14px',
        }}
      >
        <CopyrightOutlined /> 2021 Shippo
      </Footer>
    </Layout>
  )
}