Skip to content

Commit

Permalink
feat: replace apollo with urql
Browse files Browse the repository at this point in the history
  • Loading branch information
sylv committed Feb 11, 2024
1 parent fc00711 commit bdcafc8
Show file tree
Hide file tree
Showing 29 changed files with 240 additions and 271 deletions.
5 changes: 3 additions & 2 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
"watch": "concurrently \"vavite serve\" \"pnpm generate --watch\""
},
"devDependencies": {
"@0no-co/graphqlsp": "^1.3.0",
"@apollo/client": "^3.8.9",
"@atlasbot/configs": "^10.5.15",
"@fastify/early-hints": "^1.0.1",
"@fastify/http-proxy": "^9.3.0",
Expand All @@ -32,6 +30,8 @@
"@types/node": "^20.10.6",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.4.1",
"autoprefixer": "^10.4.16",
"clsx": "^2.1.0",
"concurrently": "^8.2.2",
Expand Down Expand Up @@ -61,6 +61,7 @@
"tailwindcss": "^3.4.1",
"tsup": "^8.0.1",
"typescript": "^5.3.3",
"urql": "^4.0.6",
"vavite": "^4.0.1",
"vike": "^0.4.156",
"vite": "^5.0.11",
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from 'clsx';
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import { FiArrowLeft } from 'react-icons/fi';

export interface BreadcrumbsProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/button.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable react/button-has-type */
import clsx from 'clsx';
import type { FC, HTMLAttributes } from 'react';
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import { Spinner } from './spinner';

export interface ButtonProps extends Omit<HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>, 'prefix' | 'style'> {
Expand Down
1 change: 0 additions & 1 deletion packages/web/src/components/container.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import clsx from 'clsx';
import type { FC, ReactNode } from 'react';
import React from 'react';

export interface ContainerProps {
centerX?: boolean;
Expand Down
8 changes: 3 additions & 5 deletions packages/web/src/components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Link } from '../link';
import { useToasts } from '../toast';
import { HeaderUser } from './header-user';
import { graphql } from '../../@generated';
import { useMutation } from '@apollo/client';
import { useMutation } from 'urql';

const ResendVerificationEmail = graphql(`
mutation ResendVerificationEmail($data: ResendVerificationEmailDto) {
Expand All @@ -40,7 +40,7 @@ export const Header = memo(() => {
setShowEmailInput(false);
});

const [resendMutation] = useMutation(ResendVerificationEmail);
const [, resendMutation] = useMutation(ResendVerificationEmail);
const [resendVerification, sendingVerification] = useAsync(async () => {
if (resent || !user.data) return;
if (!user.data.email && !email) {
Expand All @@ -51,9 +51,7 @@ export const Header = memo(() => {
const payload = !user.data.email && email ? { email } : null;
try {
await resendMutation({
variables: {
data: payload,
},
data: payload,
});

setShowEmailInput(false);
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/link.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { forwardRef, Fragment, type HTMLAttributes } from 'react';
import { forwardRef, type HTMLAttributes } from 'react';

export interface LinkProps extends HTMLAttributes<HTMLAnchorElement> {
href: string;
Expand Down
1 change: 0 additions & 1 deletion packages/web/src/components/spinner.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import clsx from 'clsx';
import type { FC, HTMLAttributes } from 'react';
import React from 'react';

export interface SpinnerProps extends HTMLAttributes<SVGElement> {
size?: 'small' | 'medium' | 'large';
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/components/toast/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { ToastProps } from "./toast";
import React from 'react';
import { ToastProps } from './toast';

export type ToastContextData = null | ((toast: ToastProps) => void);
export const ToastContext = React.createContext<ToastContextData>(null);
4 changes: 2 additions & 2 deletions packages/web/src/components/toast/toast-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { nanoid } from 'nanoid';
import type { FC, ReactNode } from 'react';
import React, { Fragment, useCallback, useState } from 'react';
import { useCallback, useState } from 'react';
import { ToastContext } from './context';
import type { ToastProps } from './toast';
import { Toast, TRANSITION_DURATION } from './toast';
import { TRANSITION_DURATION, Toast } from './toast';

// spread operators on arrays are to fix this
// https://stackoverflow.com/questions/56266575/why-is-usestate-not-triggering-re-render
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/toast/toast.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import clsx from 'clsx';
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';

export interface ToastProps {
text: string;
Expand Down
11 changes: 6 additions & 5 deletions packages/web/src/containers/file-list/file-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQuery } from '@apollo/client';
import type { FC } from 'react';
import { Fragment } from 'react';
import { useQuery } from 'urql';
import { graphql } from '../../@generated';
import { Breadcrumbs } from '../../components/breadcrumbs';
import { Card } from '../../components/card';
Expand Down Expand Up @@ -51,9 +51,10 @@ const GetPastesQuery = graphql(`

export const FileList: FC = () => {
const [filter, setFilter] = useQueryState('filter', 'files');
const files = useQuery(GetFilesQuery, { skip: filter !== 'files' });
const pastes = useQuery(GetPastesQuery, { skip: filter !== 'pastes' });
const [files, filesFetchMore] = useQuery({ query: GetFilesQuery, pause: filter !== 'files' });
const [pastes, pastesFetchMore] = useQuery({ query: GetPastesQuery, pause: filter !== 'pastes' });
const source = filter === 'files' ? files : pastes;
const fetchMore = filter === 'files' ? filesFetchMore : pastesFetchMore;
if (source.error) {
return <Error error={source.error} />;
}
Expand Down Expand Up @@ -102,7 +103,7 @@ export const FileList: FC = () => {
{pastes.data?.user.pastes.edges.map(({ node }) => <PasteCard key={node.id} paste={node} />)}
</div>
)}
{!source.loading && !hasContent && (
{!source.fetching && !hasContent && (
<Card className="text-gray-500">
You haven&apos;t uploaded anything yet. Once you upload something, it will appear here.
</Card>
Expand All @@ -113,7 +114,7 @@ export const FileList: FC = () => {
className="w-full bg-dark-200 px-2 py-2 text-gray-500 hover:bg-dark-300 transition"
type="button"
onClick={() => {
source.fetchMore({
fetchMore({
variables: {
after: currentPageInfo.pageInfo.endCursor,
},
Expand Down
6 changes: 3 additions & 3 deletions packages/web/src/hooks/useConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery } from '@apollo/client';
import { CombinedError, useQuery } from 'urql';
import { graphql } from '../@generated';

const ConfigQuery = graphql(`
Expand All @@ -24,9 +24,9 @@ const ConfigQuery = graphql(`
`);

export const useConfig = () => {
const config = useQuery(ConfigQuery);
const [config] = useQuery({ query: ConfigQuery });
return {
...config,
error: config.error as CombinedError | undefined,
data: config.data?.config,
};
};
22 changes: 11 additions & 11 deletions packages/web/src/hooks/useUser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TypedDocumentNode, useMutation, useQuery } from '@apollo/client';
import { useEffect, useState } from 'react';
import { CombinedError, TypedDocumentNode, useMutation, useQuery } from 'urql';
import { graphql } from '../@generated';
import type { GetUserQuery, LoginMutationVariables, RegularUserFragment } from '../@generated/graphql';
import { navigate, reload } from '../helpers/routing';
Expand Down Expand Up @@ -38,10 +38,10 @@ const LogoutMutation = graphql(`

export const useLoginUser = () => {
const [otp, setOtp] = useState(false);
const [loginMutation] = useMutation(LoginMutation);
const [, loginMutation] = useMutation(LoginMutation);
const [login] = useAsync(async (variables: LoginMutationVariables) => {
try {
await loginMutation({ variables });
await loginMutation(variables);
navigate('/dashboard');
} catch (error: any) {
if (error.message.toLowerCase().includes('otp')) {
Expand All @@ -59,7 +59,7 @@ export const useLoginUser = () => {
};

export const useLogoutUser = () => {
const [logoutMutation] = useMutation(LogoutMutation);
const [, logoutMutation] = useMutation(LogoutMutation);
const [logout] = useAsync(async () => {
await logoutMutation({});
reload();
Expand All @@ -69,27 +69,27 @@ export const useLogoutUser = () => {
};

export const useUserRedirect = (
query: { data: { user: RegularUserFragment } | null | undefined; loading: boolean; called: boolean },
query: { data?: { user: RegularUserFragment } | null | undefined; fetching: boolean },
redirect: boolean | undefined,
) => {
useEffect(() => {
if (!query.data && !query.loading && query.called && redirect) {
if (!query.data && !query.fetching && redirect) {
navigate(`/login?to=${window.location.href}`);
}
}, [redirect, query.data, query.loading, query.called]);
}, [redirect, query.data, query.fetching]);
};

export const useUser = <T extends TypedDocumentNode<GetUserQuery, any>>(redirect?: boolean, query?: T) => {
const { login, otpRequired } = useLoginUser();
const { logout } = useLogoutUser();
const { data, loading, called, error } = useQuery((query || UserQuery) as T);
const [{ data, fetching, error }] = useQuery({ query: (query || UserQuery) as T });

useUserRedirect({ data, loading, called }, redirect);
useUserRedirect({ data, fetching }, redirect);

return {
data: data?.user as RegularUserFragment | null | undefined,
loading: loading,
error: error,
fetching: fetching,
error: error as CombinedError | undefined,
otpRequired: otpRequired,
login: login,
logout: logout,
Expand Down
10 changes: 5 additions & 5 deletions packages/web/src/pages/dashboard/mfa/+Page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMutation, useQuery } from '@apollo/client';
import { useMutation, useQuery } from 'urql';
import clsx from 'clsx';
import { QRCodeSVG } from 'qrcode.react';
import { FC, Fragment, useCallback, useMemo } from 'react';
Expand Down Expand Up @@ -32,10 +32,10 @@ const ConfirmOTP = graphql(`
`);

export const Page: FC = () => {
const result = useQuery(GenerateOtp);
const [result] = useQuery({ query: GenerateOtp });
const createToast = useToasts();
const [currentStep, setCurrentStep] = useQueryState('step', 0, Number);
const [confirmOtp] = useMutation(ConfirmOTP);
const [, confirmOtp] = useMutation(ConfirmOTP);

const copyable = useMemo(() => {
if (!result.data) return;
Expand Down Expand Up @@ -64,7 +64,7 @@ export const Page: FC = () => {

const [confirm, confirming] = useAsync(async (otpCode: string) => {
try {
await confirmOtp({ variables: { otpCode } });
await confirmOtp({ otpCode });
createToast({ text: 'Successfully enabled 2FA!' });
navigate('/dashboard', { overwriteLastHistoryEntry: true });
} catch (error: any) {
Expand All @@ -77,7 +77,7 @@ export const Page: FC = () => {
}
});

if (result.loading) return <PageLoader />;
if (result.fetching) return <PageLoader />;
if (!result.data) return <Error error={result.error} />;

return (
Expand Down
19 changes: 7 additions & 12 deletions packages/web/src/pages/dashboard/preferences/+Page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useMutation, useQuery } from '@apollo/client';
import { FC, Fragment } from 'react';
import { useMutation, useQuery } from 'urql';
import { graphql } from '../../../@generated';
import { GetUserDocument } from '../../../@generated/graphql';
import { Breadcrumbs } from '../../../components/breadcrumbs';
import { Button } from '../../../components/button';
import { Container } from '../../../components/container';
Expand Down Expand Up @@ -39,22 +38,20 @@ const UserQueryWithToken = graphql(`
`);

export const Page: FC = () => {
const user = useQuery(UserQueryWithToken);
const [user] = useQuery({ query: UserQueryWithToken });
const { logout } = useLogoutUser();
const [refreshMutation] = useMutation(RefreshToken);
const [, refreshMutation] = useMutation(RefreshToken);
const [refresh, refreshing] = useAsync(async () => {
// eslint-disable-next-line no-alert
const confirmation = confirm('Are you sure? This will invalidate all existing configs and sessions and will sign you out of the dashboard.') // prettier-ignore
if (!confirmation) return;
await refreshMutation();
await refreshMutation({});
await logout();
});

useUserRedirect(user, true);

const [disableOTP, disableOTPMut] = useMutation(DisableOtp, {
refetchQueries: [{ query: GetUserDocument }],
});
const [disableOTPMut, disableOTP] = useMutation(DisableOtp);

return (
<Container>
Expand Down Expand Up @@ -125,11 +122,9 @@ export const Page: FC = () => {
<div className="right flex items-center col-span-full md:col-span-1">
{user.data && user.data.user.otpEnabled && (
<OtpInput
loading={disableOTPMut.loading}
loading={disableOTPMut.fetching}
onCode={(otpCode) => {
disableOTP({
variables: { otpCode },
});
disableOTP({ otpCode });
}}
/>
)}
Expand Down
15 changes: 7 additions & 8 deletions packages/web/src/pages/file/@fileId/+Page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useMutation, useQuery } from '@apollo/client';
import clsx from 'clsx';
import copyToClipboard from 'copy-to-clipboard';
import type { FC, ReactNode } from 'react';
import { Fragment, useState } from 'react';
import { FiDownload, FiShare, FiTrash } from 'react-icons/fi';
import { useMutation, useQuery } from 'urql';
import { graphql } from '../../../@generated';
import { Container } from '../../../components/container';
import { Embed } from '../../../components/embed/embed';
Expand Down Expand Up @@ -72,14 +72,15 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
const [deleteKey] = useQueryState<string | undefined>('deleteKey');
const [confirm, setConfirm] = useState(false);
const createToast = useToasts();
const file = useQuery(GetFile, {
skip: !fileId,
const [file] = useQuery({
query: GetFile,
pause: !fileId,
variables: {
fileId: fileId as string,
},
});

const [deleteMutation] = useMutation(DeleteFile);
const [, deleteMutation] = useMutation(DeleteFile);
const copyLink = () => {
copyToClipboard(file.data?.file.urls.view ?? window.location.href);
createToast({
Expand All @@ -100,10 +101,8 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
}

await deleteMutation({
variables: {
fileId: file.data.file.id,
deleteKey: deleteKey,
},
fileId: file.data.file.id,
deleteKey: deleteKey,
});

createToast({ text: `Deleted "${file.data.file.displayName}"` });
Expand Down
Loading

0 comments on commit bdcafc8

Please sign in to comment.