@ant-design/icons#CameraOutlined TypeScript Examples

The following examples show how to use @ant-design/icons#CameraOutlined. 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: CoverPhotoOverlay.tsx    From foodie with MIT License 5 votes vote down vote up
CoverPhotoOverlay: React.FC<IProps> = (props) => {
    return (
        <div
            className={`w-full h-full laptop:bg-black laptop:bg-opacity-50 absolute flex items-center justify-center laptop:invisible transition-all ${props.coverPhoto.imageFile.file ? 'z-10' : 'z-0'}`}
            ref={props.coverPhotoOverlayRef}
        >
            <input
                type="file"
                hidden
                accept="image/*"
                onChange={props.coverPhoto.onFileChange}
                readOnly={props.isUploadingCoverPhoto}
                id="cover"
            />
            {props.isOwnProfile && (
                <>
                    {props.isUploadingCoverPhoto ? <Loader mode="light" /> : (
                        <>
                            {props.coverPhoto.imageFile.file ? (
                                <div className="flex">
                                    <button className="button--danger !rounded-full" onClick={props.coverPhoto.clearFiles}>
                                        <CloseOutlined className="text-xl text-white" />
                                    </button>
                                            &nbsp;
                                    <label
                                        className="button--muted !rounded-full cursor-pointer"
                                        htmlFor="cover"
                                    >
                                        Change
                                            </label>
                                            &nbsp;
                                    <button onClick={props.handleSaveCoverPhoto}>Save</button>
                                </div>
                            ) : (
                                <label
                                    className="p-3 laptop:p-4 bg-indigo-700 absolute right-4 top-4  laptop:relative text-white font-medium rounded-full cursor-pointer hover:bg-indigo-800"
                                    htmlFor="cover"
                                >
                                    {window.screen.width > 800 ? 'Change Cover Photo' : (
                                        <CameraOutlined className="text-xl text-white" />
                                    )}
                                </label>

                            )}
                        </>
                    )}
                </>
            )}

        </div>
    );
}
Example #2
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 #3
Source File: index.tsx    From foodie with MIT License 4 votes vote down vote up
Header: React.FC<IProps> = ({ profile, auth }) => {
    const [isUploadingProfileImage, setIsUploadingProfileImage] = useState(false);
    const [isUploadingCoverPhoto, setIsUploadingCoverPhoto] = useState(false);
    const history = useHistory();
    const { isOpen, openModal, closeModal } = useModal();
    const dispatch = useDispatch();
    const coverPhotoOverlayRef = useRef<HTMLDivElement | null>(null);
    const coverPhotoRef = useRef<HTMLDivElement | null>(null);
    const coverPhoto = useFileHandler<IImage>('single', initImageState);
    const profilePicture = useFileHandler<IImage>('single', initImageState);

    useEffect(() => {
        const cp = coverPhotoRef.current;
        const cpo = coverPhotoOverlayRef.current;

        if (cp && cpo && profile.isOwnProfile && window.screen.width > 800) {
            cp.addEventListener('mouseover', overlayOnMouseOver);
            cp.addEventListener('mouseout', overlayOnMouseOut);
        }

        return () => {
            if (cp && cpo) {
                cp.removeEventListener('mouseover', overlayOnMouseOver);
                cp.removeEventListener('mouseout', overlayOnMouseOut);
            }
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [coverPhoto.imageFile.file, isUploadingCoverPhoto, profile.isOwnProfile]);

    const overlayOnMouseOver = () => {
        if (!isUploadingCoverPhoto && coverPhotoOverlayRef.current) {
            coverPhotoOverlayRef.current.style.visibility = 'visible';
        }
    }

    const overlayOnMouseOut = () => {
        if (!isUploadingCoverPhoto && !coverPhoto.imageFile.file && coverPhotoOverlayRef.current) {
            coverPhotoOverlayRef.current.style.visibility = 'hidden';
        }
    }

    const handleProfilePictureFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        profilePicture.onFileChange(e, () => {
            openModal();
        });
    };

    const onCropSuccessCallback = async (file: File) => {
        const formData = new FormData();
        formData.append('photo', file);

        try {
            setIsUploadingProfileImage(true);
            toast('Uploading...', { hideProgressBar: true, bodyStyle: { color: '#1a1a1a' } });

            const { image } = await uploadPhoto(formData, 'picture');

            dispatch(updateProfilePicture(image));
            dispatch(updateAuthPicture(image));
            setIsUploadingProfileImage(false);

            toast.dismiss();
            toast.dark('Profile picture successfully changed.', { hideProgressBar: true });
        } catch (e) {
            console.log(e);
            setIsUploadingProfileImage(false);
            toast.error(e.error.message);
        }
    };

    const handleSaveCoverPhoto = async () => {
        if (coverPhoto.imageFile.file) {
            const formData = new FormData();
            formData.append('photo', coverPhoto.imageFile.file);

            try {
                setIsUploadingCoverPhoto(true);
                toast('Uploading Cover Photo...', { hideProgressBar: true, bodyStyle: { color: '#1a1a1a' } });

                const { image } = await uploadPhoto(formData, 'cover');

                dispatch(updateCoverPhoto(image));
                setIsUploadingCoverPhoto(false);

                coverPhoto.clearFiles();
                toast.dismiss();
                toast.dark('Cover photo successfully changed.', { hideProgressBar: true });
            } catch (e) {
                console.log(e);
                setIsUploadingCoverPhoto(false);
                toast.error(e.error.message);
            }
        }
    }

    const onClickMessage = () => {
        dispatch(initiateChat({
            username: profile.username,
            id: profile.id,
            fullname: profile.fullname || '',
            profilePicture: profile.profilePicture?.url || ''
        }));

        if (window.screen.width < 1024) {
            history.push(`/chat/${profile.username}`);
        }
    }

    return (
        <div>
            <CropProfileModal
                isOpen={isOpen}
                closeModal={closeModal}
                openModal={openModal}
                file={profilePicture.imageFile}
                onCropSuccessCallback={onCropSuccessCallback}
            />
            {/*  ----- COVER PHOTO ------- */}
            <div className="w-full h-60 mb-8 laptop:mb-0 laptop:h-80 bg-gray-200 dark:bg-gray-800 relative overflow-hidden" ref={coverPhotoRef}>
                {/* ---- OVERLAY FOR CHOOSING PHOTO AND SHOWING LOADER ----- */}
                <CoverPhotoOverlay
                    coverPhotoOverlayRef={coverPhotoOverlayRef}
                    coverPhoto={coverPhoto}
                    isUploadingCoverPhoto={isUploadingCoverPhoto}
                    isOwnProfile={profile.isOwnProfile}
                    handleSaveCoverPhoto={handleSaveCoverPhoto}
                />
                {/* ---- ACTUAL COVER PHOTO ---- */}
                <img
                    alt=""
                    className="w-full h-full object-cover"
                    src={coverPhoto.imageFile.url || profile.coverPhoto?.url || `https://source.unsplash.com/oDhGIbegZNI/1400x900`}
                />
            </div>
            <div className="laptop:px-6% w-full relative flex mt-2 laptop:transform laptop:-translate-y-2/4">
                {/* --- PROFILE PICTURE */}
                <div className="absolute left-0 right-0 mx-auto w-40 h-40 transform -translate-y-44 laptop:transform-none laptop:relative laptop:w-1/3 laptop:h-60 laptop:mr-2 flex justify-center">
                    {(!coverPhoto.imageFile.file) && (
                        <>
                            <div

                                className="w-full h-full laptop:w-60 laptop:h-60 !bg-cover !bg-no-repeat rounded-full border-4 border-white dark:border-indigo-1000 overflow-hidden"
                                style={{
                                    background: `#f7f7f7 url(${profile.profilePicture?.url || avatar_placeholder})`
                                }}
                            >
                                {isUploadingProfileImage && (
                                    <div className="w-full h-full bg-black bg-opacity-50 flex items-center justify-center">
                                        <Loader mode="light" />
                                    </div>
                                )}
                            </div>
                            {/* ---- UPDLOAD PROFILE PICTURE ---- */}
                            {profile.isOwnProfile && (
                                <div>
                                    <input
                                        type="file"
                                        hidden
                                        accept="image/*"
                                        onChange={handleProfilePictureFileChange}
                                        readOnly={isUploadingProfileImage}
                                        id="picture"
                                    />
                                    <label
                                        htmlFor="picture"
                                    >
                                        <div className="flex items-center w-10 h-10 justify-center cursor-pointer p-4 bg-indigo-700 rounded-full absolute -bottom-2 laptop:bottom-0 left-14 hover:bg-indigo-800">
                                            <CameraOutlined className="text-xl flex items-center justify-center text-white" />
                                        </div>
                                    </label>
                                </div>
                            )}
                        </>
                    )}
                </div>
                <div className="flex w-full  flex-col self-end">
                    <div className="px-4 laptop:px-0 w-full flex items-center flex-col laptop:flex-row justify-between mb-2 laptop:ml-2 laptop:mr-14">
                        {/* ---- NAME AND USERNAME */}
                        <div className="text-center laptop:text-left mb-4 laptop:mb-0">
                            <h2 className="text-3xl dark:text-white">{profile.fullname || `@${profile.username}`}</h2>
                            <span className="text-indigo-700 dark:text-indigo-400">{profile.fullname && `@${profile.username}`}</span>
                        </div>
                        {/* ---- FOLLOW/UNFOLLOW/MESSAGE BUTTON */}
                        {!profile.isOwnProfile ? (
                            <div className="flex justify-center laptop:justify-start space-x-4 items-start">
                                <FollowButton isFollowing={profile.isFollowing} userID={profile.id} />
                                <button
                                    className="button--muted !border-gray-400 !rounded-full flex items-center dark:bg-indigo-1100 dark:text-white dark:hover:text-white dark:hover:bg-indigo-900 dark:!border-gray-800"
                                    onClick={onClickMessage}
                                >
                                    <MessageOutlined className="flex items-center justify-center mr-2" />
                                    Message
                                </button>
                            </div>
                        ) : (
                            <button
                                className="button--muted !rounded-full !border !border-gray-400 !focus:bg-gray-200 !py-2 flex items-center justify-center dark:bg-indigo-1100 dark:text-white dark:hover:text-white dark:hover:bg-indigo-900 dark:!border-gray-800"
                                onClick={() => history.push(`/user/${profile.username}/edit`)}
                            >
                                <EditOutlined className="text-xl mr-4" />
                                    Edit Profile
                            </button>
                        )}
                    </div>
                    {/* ---- PROFILE NAVS ----- */}
                    <Tabs
                        username={profile.username}
                        isOwnProfile={profile.id === auth.id}
                        followersCount={profile.followersCount}
                        followingCount={profile.followingCount}
                    />
                </div>
            </div>
        </div>
    );
}
Example #4
Source File: index.tsx    From nanolooker with MIT License 4 votes vote down vote up
Search = ({ isHome = false }) => {
  const { t } = useTranslation();
  const { theme } = React.useContext(PreferencesContext);
  const { knownAccounts } = React.useContext(KnownAccountsContext);
  const { bookmarks } = React.useContext(BookmarksContext);
  const hasAccountBookmarks = !!Object.keys(bookmarks?.account || {}).length;
  const [isExpanded, setIsExpanded] = React.useState(isHome);
  const [isError, setIsError] = React.useState(false);
  const [filteredResults, setFilteredResults] = React.useState([] as any);
  const { searchValue, setSearchValue } = useSearch();
  const [accountBookmarks, setAccountBookmarks] = React.useState<
    { alias: string; account: string }[]
  >([]);
  const {
    searchHistory,
    addSearchHistory,
    removeSearchHistory,
  } = useSearchHistory();
  const searchRef = React.useRef(null);
  const [isOpen, setIsOpen] = React.useState(false);
  const [invalidQrCode, setInvalidQrCode] = React.useState("");

  let history = useHistory();

  const validateSearch = React.useCallback(
    async (value: any) => {
      if (!value) {
        setIsError(false);
        setFilteredResults([]);
      } else {
        const isValidAccount = isValidAccountAddress(value);
        const isValidBlock = isValidBlockHash(value);

        setIsError(!isValidAccount && !isValidBlock && value.length > 30);

        if (isValidBlock) {
          addSearchHistory(value.toUpperCase());
          history.push(`/block/${value.toUpperCase()}`);
        } else if (isValidAccount) {
          let account = getPrefixedAccount(value);

          setSearchValue(account);
          addSearchHistory(account);
          history.push(`/account/${account}`);
        } else {
          const filteredKnownAccounts = knownAccounts
            .filter(({ alias }) =>
              alias.toLowerCase().includes(value.toLowerCase()),
            )
            .map(item => renderItem(item));

          const filteredAccountBookmarks = accountBookmarks
            .filter(({ alias }) =>
              alias.toLowerCase().includes(value.toLowerCase()),
            )
            .map(item => renderItem(item as KnownAccount));

          setFilteredResults(
            filteredAccountBookmarks.concat(filteredKnownAccounts),
          );
        }
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [addSearchHistory, knownAccounts, accountBookmarks],
  );

  React.useEffect(() => {
    if (hasAccountBookmarks) {
      setAccountBookmarks(
        Object.entries(bookmarks?.account).map(([account, alias]) => ({
          account,
          alias,
        })),
      );
    } else {
      setAccountBookmarks([]);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [hasAccountBookmarks]);

  React.useEffect(() => {
    validateSearch(searchValue);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchValue]);

  React.useEffect(() => {
    if (!isOpen) return;

    function onScanSuccess(qrMessage: any) {
      if (isValidAccountAddress(qrMessage)) {
        setIsOpen(false);
        setSearchValue(getPrefixedAccount(qrMessage));
        document.getElementById("html5-qrcode-scan-stop-btn")?.click();
      } else {
        setInvalidQrCode(qrMessage);
      }
    }

    const html5QrcodeScanner = new window.Html5QrcodeScanner(
      `qrcode-reader-search${isHome ? "-home" : ""}`,
      {
        fps: 10,
        qrbox: 250,
      },
    );
    html5QrcodeScanner.render(onScanSuccess);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isOpen]);

  const renderItem = ({ alias, account }: KnownAccount) => ({
    value: account,
    label: (
      <>
        <strong style={{ display: "block" }}>{alias}</strong>
        {account}
      </>
    ),
  });

  return (
    <>
      <AutoComplete
        style={{
          float: isExpanded ? "right" : "none",
          maxWidth: "calc(100vw - 24px)",
          width: isExpanded ? "650px" : "100%",
          // transitionDelay: `${isExpanded ? 0 : 0.2}s`,
        }}
        dropdownClassName={`search-autocomplete-dropdown ${
          theme === Theme.DARK ? "theme-dark" : ""
        }`}
        dropdownStyle={{
          maxWidth: "calc(100vw - 40px)",
        }}
        options={filteredResults}
        // @ts-ignore
        onSelect={validateSearch}
        onChange={value => {
          setSearchValue(value);
        }}
        // @ts-ignore
        onPaste={e => {
          e.preventDefault();

          // @ts-ignore
          const paste = (e.clipboardData || window.clipboardData).getData(
            "text",
          );

          const account = getAccountAddressFromText(paste);
          const hash = getAccountBlockHashFromText(paste);
          if (account || hash) {
            setSearchValue(account || hash);
          } else {
            setSearchValue(paste);
          }
        }}
        value={searchValue}
      >
        <Input
          ref={searchRef}
          allowClear
          suffix={
            <>
              <CameraOutlined
                onClick={() => setIsOpen(true)}
                className="search-history-icon"
                style={{ padding: "6px", marginRight: "3px" }}
              />
              <Dropdown
                key="search-history-dropdown"
                overlayStyle={{ zIndex: 1050 }}
                overlayClassName={theme === Theme.DARK ? "theme-dark" : ""}
                overlay={
                  <Menu>
                    {!searchHistory.length ? (
                      <Menu.Item disabled>{t("search.noHistory")}</Menu.Item>
                    ) : (
                      searchHistory.map(history => (
                        <Menu.Item
                          onClick={() => setSearchValue(history)}
                          key={history}
                        >
                          <div
                            className="color-normal"
                            style={{
                              display: "flex",
                              alignItems: "flex-start",
                            }}
                          >
                            <div>
                              {isValidAccountAddress(history) ? (
                                <WalletOutlined />
                              ) : (
                                <BlockOutlined />
                              )}
                            </div>
                            <div
                              className="break-word"
                              style={{ margin: "0 6px", whiteSpace: "normal" }}
                            >
                              {history}
                            </div>
                            <DeleteButton
                              onClick={(e: Event) => {
                                e.stopPropagation();
                                removeSearchHistory(history);
                              }}
                            />
                          </div>
                        </Menu.Item>
                      ))
                    )}
                  </Menu>
                }
                placement="bottomRight"
              >
                <HistoryOutlined
                  className="search-history-icon"
                  style={{ padding: "6px", marginRight: "6px" }}
                />
              </Dropdown>
              <SearchOutlined />
            </>
          }
          className={`ant-input-search ${isError ? "has-error" : ""}`}
          placeholder={t("search.searchBy")}
          onFocus={({ target: { value } }) => {
            validateSearch(value);
            setIsExpanded(true);
          }}
          onBlur={() => setIsExpanded(isHome || false)}
          size={isHome ? "large" : "middle"}
          spellCheck={false}
        />
      </AutoComplete>
      <Modal
        title={t("search.scanWallet")}
        visible={isOpen}
        onCancel={() => setIsOpen(false)}
        footer={[
          <Button key="back" onClick={() => setIsOpen(false)}>
            {t("common.cancel")}
          </Button>,
        ]}
      >
        {invalidQrCode ? (
          <Alert
            message={t("pages.nanoquakejs.invalidAccount")}
            description={invalidQrCode}
            type="error"
            showIcon
            style={{ marginBottom: 12 }}
          />
        ) : null}
        <div
          id={`qrcode-reader-search${isHome ? "-home" : ""}`}
          className="qrcode-reader"
        ></div>
      </Modal>
    </>
  );
}
Example #5
Source File: Register.tsx    From nanolooker with MIT License 4 votes vote down vote up
Register: React.FC = () => {
  const { t } = useTranslation();
  const [isOpen, setIsOpen] = React.useState(false);
  const [isSending, setIsSending] = React.useState(false);
  const [registerError, setRegisterError] = React.useState("");
  const [invalidQrCode, setInvalidQrCode] = React.useState("");
  const [section, setSection] = React.useState(Sections.REGISTER);
  const {
    nanoQuakeJSUsername,
    setNanoQuakeJSUsername,
    nanoQuakeJSAccount,
    setNanoQuakeJSAccount,
  } = React.useContext(PreferencesContext);

  const {
    control,
    handleSubmit,
    trigger,
    setValue,
    getValues,
    formState: { errors, isValid },
  } = useForm({
    defaultValues: {
      username: nanoQuakeJSUsername || "",
      account: nanoQuakeJSAccount || "",
    },
    mode: "onChange",
  });
  const onSubmit = async ({
    username,
    account,
  }: {
    username: string;
    account: string;
  }) => {
    setIsSending(true);
    setRegisterError("");

    // Prefix account with nano_
    const address = getPrefixedAccount(account);

    try {
      const res = await fetch("/api/nanoquakejs/register", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          username,
          address,
        }),
      });
      const json = await res.json();
      if (!json.error) {
        setNanoQuakeJSUsername(username);
        setNanoQuakeJSAccount(address);
        setIsOpen(false);
        Tracker.ga4?.gtag("event", "NanoQuakeJS - Register");
      } else {
        setRegisterError(
          json.error === "already_registered"
            ? t("pages.nanoquakejs.registerErrorUsername")
            : t("pages.nanoquakejs.registerError"),
        );
      }
    } catch (err) {
      setRegisterError(t("pages.nanoquakejs.registerError"));
    }

    setIsSending(false);
  };

  React.useEffect(() => {
    if (!isOpen) {
      setSection(Sections.REGISTER);
      setInvalidQrCode("");
      setRegisterError("");
    }
  }, [isOpen]);

  React.useEffect(() => {
    if (section !== Sections.SCAN) return;

    function onScanSuccess(qrMessage: any) {
      if (isValidAccountAddress(qrMessage)) {
        setValue("account", getPrefixedAccount(qrMessage));
        trigger("account");

        document.getElementById("html5-qrcode-scan-stop-btn")?.click();
        setSection(Sections.REGISTER);
      } else {
        setInvalidQrCode(qrMessage);
      }
    }

    const html5QrcodeScanner = new window.Html5QrcodeScanner("qrcode-reader", {
      fps: 10,
      qrbox: 250,
    });
    html5QrcodeScanner.render(onScanSuccess);

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [section]);

  return (
    <>
      <Row
        style={{
          textAlign: "center",
          paddingBottom: "3px",
          border: "none",
          marginTop: -12,
        }}
      >
        <Col xs={24}>
          <Space size={12} align="center" direction="vertical">
            {nanoQuakeJSUsername && nanoQuakeJSAccount ? (
              <Play />
            ) : (
              <Button
                type="primary"
                size="large"
                shape="round"
                onClick={() => setIsOpen(true)}
              >
                {t("pages.nanoquakejs.register")}
              </Button>
            )}

            <QRCodeModal
              account={NANOQUAKEJS_DONATION_ACCOUNT}
              header={<Text>NanoQuakeJS</Text>}
            >
              <Button ghost type="primary" size="small" shape="round">
                {t("pages.nanoquakejs.donatePrizePool")}
              </Button>
            </QRCodeModal>

            <p className="default-color" style={{ textAlign: "left" }}>
              {t("pages.nanoquakejs.payoutDescription")}
            </p>
          </Space>
        </Col>
      </Row>

      <Modal
        title={
          section === Sections.REGISTER
            ? t("pages.nanoquakejs.register")
            : t("pages.nanoquakejs.scanWallet")
        }
        visible={isOpen}
        // @ts-ignore
        onOk={
          Sections.REGISTER
            ? handleSubmit(onSubmit)
            : setSection(Sections.REGISTER)
        }
        okText={t("pages.nanoquakejs.register")}
        okButtonProps={{
          disabled: !isValid,
        }}
        confirmLoading={isSending}
        onCancel={() => {
          section === Sections.REGISTER
            ? setIsOpen(false)
            : setSection(Sections.REGISTER);
        }}
        cancelText={t("common.cancel")}
      >
        {section === Sections.REGISTER ? (
          <>
            {registerError ? (
              <Alert
                message={registerError}
                type="error"
                showIcon
                style={{ marginBottom: 12 }}
              />
            ) : null}
            <form onSubmit={handleSubmit(onSubmit)}>
              <Space size={12} direction="vertical" style={{ width: "100%" }}>
                <Text>{t("pages.nanoquakejs.registerDescription")}</Text>

                <Space size={3} direction="vertical" style={{ width: "100%" }}>
                  <Text>{t("pages.nanoquakejs.inGameUsername")}</Text>
                  <Controller
                    render={({ field }) => (
                      <Input
                        {...field}
                        type="text"
                        readOnly={isSending}
                        maxLength={32}
                        autoFocus={!!getValues("username")}
                        suffix={
                          getValues("username") && !errors?.username ? (
                            <CheckCircleTwoTone twoToneColor={"#52c41a"} />
                          ) : (
                            " "
                          )
                        }
                      />
                    )}
                    rules={{
                      validate: (value: string) =>
                        value.length >= 3 && !/\s/.test(value),
                    }}
                    control={control}
                    name="username"
                    defaultValue={getValues("username")}
                  />
                </Space>
                <Space size={3} direction="vertical" style={{ width: "100%" }}>
                  <Text>{t("pages.nanoquakejs.accountReceivePayouts")}</Text>
                  <Controller
                    render={({ field }) => (
                      <Input
                        {...field}
                        readOnly={isSending}
                        placeholder="nano_"
                        suffix={
                          getValues("account") && !errors?.account ? (
                            <CheckCircleTwoTone twoToneColor={"#52c41a"} />
                          ) : (
                            <Button
                              size="small"
                              type="text"
                              style={{ margin: "-1px -7px -1px" }}
                              onClick={() => setSection(Sections.SCAN)}
                            >
                              <CameraOutlined />
                            </Button>
                          )
                        }
                      />
                    )}
                    rules={{
                      validate: (value: string) => isValidAccountAddress(value),
                    }}
                    control={control}
                    name="account"
                    defaultValue={getValues("account")}
                  />
                </Space>
                <Text style={{ fontSize: 12 }} className="color-muted">
                  * {t("pages.nanoquakejs.registerNote")}
                </Text>
              </Space>
            </form>
          </>
        ) : null}
        {section === Sections.SCAN ? (
          <>
            {invalidQrCode ? (
              <Alert
                message={t("pages.nanoquakejs.invalidAccount")}
                description={invalidQrCode}
                type="error"
                showIcon
                style={{ marginBottom: 12 }}
              />
            ) : null}
            <div id="qrcode-reader" className="qrcode-reader"></div>
          </>
        ) : null}
      </Modal>
    </>
  );
}