diff --git a/client/cms/src/components/events/event-join.dialog.view.tsx b/client/cms/src/components/events/event-join.dialog.view.tsx
index 27bf33e..2803859 100644
--- a/client/cms/src/components/events/event-join.dialog.view.tsx
+++ b/client/cms/src/components/events/event-join.dialog.view.tsx
@@ -1,7 +1,7 @@
import type { EventInfo } from './types';
-import { Loader2 } from 'lucide-react';
import { Button } from '../ui/button';
import { DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../ui/dialog';
+import { Spinner } from '../ui/spinner';
export function EventJoinDialogView({ event, onJoinEvent, isPending }: { event: EventInfo; onJoinEvent: () => void; isPending: boolean }) {
return (
@@ -19,7 +19,7 @@ export function EventJoinDialogView({ event, onJoinEvent, isPending }: { event:
-
+
);
diff --git a/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx b/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx
index 19f23d6..05bc529 100644
--- a/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx
+++ b/client/cms/src/components/events/kyc/kyc-method-selection.dialog.view.tsx
@@ -1,6 +1,5 @@
import type { KycSubmission } from './kyc.types';
import { useForm } from '@tanstack/react-form';
-import { Loader2 } from 'lucide-react';
import { useState } from 'react';
import { toast } from 'sonner';
import z from 'zod';
@@ -12,6 +11,7 @@ import {
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import { Spinner } from '@/components/ui/spinner';
import { Button } from '../../ui/button';
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog';
@@ -81,7 +81,7 @@ function CnridForm({ onSubmit }: { onSubmit: OnSubmit }) {
[state.canSubmit, state.isPristine, state.isSubmitting]}
children={([canSubmit, isPristine, isSubmitting]) => (
-
+
)}
/>
diff --git a/client/cms/src/components/login-form.tsx b/client/cms/src/components/login-form.tsx
index d03042f..b28f957 100644
--- a/client/cms/src/components/login-form.tsx
+++ b/client/cms/src/components/login-form.tsx
@@ -3,7 +3,6 @@ import type { AuthorizeSearchParams } from '@/routes/authorize';
import { Turnstile } from '@marsidev/react-turnstile';
import { useForm } from '@tanstack/react-form';
import { useNavigate } from '@tanstack/react-router';
-import { Loader2 } from 'lucide-react';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import z from 'zod';
@@ -18,6 +17,7 @@ import {
import { Input } from '@/components/ui/input';
import { useGetMagicLink } from '@/hooks/data/useGetMagicLink';
import { cn } from '@/lib/utils';
+import { Spinner } from './ui/spinner';
export function LoginForm({
oauthParams,
@@ -91,7 +91,7 @@ export function LoginForm({
diff --git a/client/cms/src/components/profile/edit-profile.dialog.view.tsx b/client/cms/src/components/profile/edit-profile.dialog.view.tsx
index 884800d..f6f8718 100644
--- a/client/cms/src/components/profile/edit-profile.dialog.view.tsx
+++ b/client/cms/src/components/profile/edit-profile.dialog.view.tsx
@@ -1,6 +1,5 @@
import type { ServiceUserUserInfoData } from '@/client';
import { useForm } from '@tanstack/react-form';
-import { Loader2 } from 'lucide-react';
import {
useEffect,
useState,
@@ -25,6 +24,7 @@ import {
import {
Input,
} from '@/components/ui/input';
+import { Spinner } from '../ui/spinner';
import { Switch } from '../ui/switch';
const formSchema = z.object({
@@ -168,7 +168,7 @@ export function EditProfileDialogView({ user, updateProfile }: { user: ServiceUs
selector={state => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
)}
/>
diff --git a/client/cms/src/components/profile/profile.view.tsx b/client/cms/src/components/profile/profile.view.tsx
index 7cd5438..295957d 100644
--- a/client/cms/src/components/profile/profile.view.tsx
+++ b/client/cms/src/components/profile/profile.view.tsx
@@ -6,13 +6,14 @@ import {
isEmpty,
isNil,
} from 'lodash-es';
-import { Loader2, Mail, Pencil } from 'lucide-react';
+import { Mail, Pencil } from 'lucide-react';
import { useMemo, useState } from 'react';
import Markdown from 'react-markdown';
import { toast } from 'sonner';
import { Avatar, AvatarImage } from '@/components/ui/avatar';
import { base64ToUtf8 } from '@/lib/utils';
import { Button } from '../ui/button';
+import { Spinner } from '../ui/spinner';
import { EditProfileDialogContainer } from './edit-profile.dialog.container';
export function ProfileView({ user, onSaveBio }: { user: ServiceUserUserInfoData; onSaveBio: (bio: string) => Promise }) {
@@ -54,12 +55,12 @@ export function ProfileView({ user, onSaveBio }: { user: ServiceUserUserInfoData
{/* Bio */}
{enableBioEdit
? (
-
- )
+
+ )
: {bio}
}
diff --git a/client/cms/src/components/ui/spinner.tsx b/client/cms/src/components/ui/spinner.tsx
new file mode 100644
index 0000000..a70e713
--- /dev/null
+++ b/client/cms/src/components/ui/spinner.tsx
@@ -0,0 +1,16 @@
+import { Loader2Icon } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
+ return (
+
+ )
+}
+
+export { Spinner }
diff --git a/client/cms/src/routes/token.tsx b/client/cms/src/routes/token.tsx
index e619c33..9d418cf 100644
--- a/client/cms/src/routes/token.tsx
+++ b/client/cms/src/routes/token.tsx
@@ -2,10 +2,10 @@ import { useMutation } from '@tanstack/react-query';
import { createFileRoute, useNavigate } from '@tanstack/react-router';
import {
useEffect,
- useState,
} from 'react';
import z from 'zod';
import { postAuthTokenMutation } from '@/client/@tanstack/react-query.gen';
+import { Spinner } from '@/components/ui/spinner';
import { setAccessToken, setRefreshToken } from '@/lib/token';
const tokenCodeSchema = z.object({
@@ -19,27 +19,33 @@ export const Route = createFileRoute('/token')({
function RouteComponent() {
const { code } = Route.useSearch();
- const [status, setStatus] = useState('Loading...');
const navigate = useNavigate();
- const mutation = useMutation({
+ const { mutate } = useMutation({
...postAuthTokenMutation(),
onSuccess: (data) => {
setAccessToken(data.data!.access_token!);
setRefreshToken(data.data!.refresh_token!);
void navigate({ to: '/' });
},
- onError: () => {
- setStatus('Error getting token');
- },
+ throwOnError: true,
});
useEffect(() => {
- if (mutation.isIdle) {
- mutation.mutate({ body: { code } });
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ const controller = new AbortController();
+ mutate({
+ body: { code },
+ signal: controller.signal,
+ });
- return {status}
;
+ return () => {
+ controller.abort();
+ };
+ }, [code, mutate]);
+
+ return (
+
+
+
+ );
}