diff --git a/client/cms/src/components/events/event-join.dialog.container.tsx b/client/cms/src/components/events/event-join.dialog.container.tsx
index 4bd056d..e447f44 100644
--- a/client/cms/src/components/events/event-join.dialog.container.tsx
+++ b/client/cms/src/components/events/event-join.dialog.container.tsx
@@ -6,7 +6,7 @@ import { Dialog } from '../ui/dialog';
import { EventJoinDialogView } from './event-join.dialog.view';
export function EventJoinDialogContainer({ event, children }: { event: EventInfo; children: React.ReactNode }) {
- const { mutateAsync } = useJoinEvent();
+ const { mutateAsync, isPending } = useJoinEvent();
const join = useCallback(() => {
mutateAsync({ body: { event_id: event.eventId } }).then(() => {
toast('加入活动成功');
@@ -19,7 +19,7 @@ export function EventJoinDialogContainer({ event, children }: { event: EventInfo
return (
);
}
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 3a90d1f..27bf33e 100644
--- a/client/cms/src/components/events/event-join.dialog.view.tsx
+++ b/client/cms/src/components/events/event-join.dialog.view.tsx
@@ -1,8 +1,9 @@
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';
-export function EventJoinDialogView({ event, onJoinEvent }: { event: EventInfo; onJoinEvent: () => void }) {
+export function EventJoinDialogView({ event, onJoinEvent, isPending }: { event: EventInfo; onJoinEvent: () => void; isPending: boolean }) {
return (
@@ -18,7 +19,7 @@ export function EventJoinDialogView({ event, onJoinEvent }: { event: EventInfo;
-
+
);
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 238f666..19f23d6 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,5 +1,6 @@
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';
@@ -80,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 f2f5c05..d680048 100644
--- a/client/cms/src/components/login-form.tsx
+++ b/client/cms/src/components/login-form.tsx
@@ -2,6 +2,7 @@ import type { TurnstileInstance } from '@marsidev/react-turnstile';
import type { AuthorizeSearchParams } from '@/routes/authorize';
import { Turnstile } from '@marsidev/react-turnstile';
import { useNavigate } from '@tanstack/react-router';
+import { Loader2 } from 'lucide-react';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import NixOSLogo from '@/assets/nixos.svg?react';
@@ -41,6 +42,7 @@ export function LoginForm({
});
};
+ const isLoading = isPending || token === null;
return (
[state.canSubmit]}
- children={([canSubmit]) => (
-
+ 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 5981f0b..c0eb78d 100644
--- a/client/cms/src/components/profile/profile.view.tsx
+++ b/client/cms/src/components/profile/profile.view.tsx
@@ -6,7 +6,7 @@ import {
isEmpty,
isNil,
} from 'lodash-es';
-import { Mail, Pencil } from 'lucide-react';
+import { Loader2, Mail, Pencil } from 'lucide-react';
import { useMemo, useState } from 'react';
import Markdown from 'react-markdown';
import { toast } from 'sonner';
@@ -18,6 +18,7 @@ import { EditProfileDialogContainer } from './edit-profile.dialog.container';
export function ProfileView({ user, onSaveBio }: { user: ServiceUserUserInfoData; onSaveBio: (bio: string) => Promise }) {
const [bio, setBio] = useState(() => base64ToUtf8(user.bio ?? ''));
const [enableBioEdit, setEnableBioEdit] = useState(false);
+ const [isSubmittingBio, setIsSubmittingBio] = useState(false);
const IdentIcon = useMemo(() => {
const avatar = createAvatar(identicon, {
@@ -53,12 +54,12 @@ export function ProfileView({ user, onSaveBio }: { user: ServiceUserUserInfoData
{/* Bio */}
{enableBioEdit
? (
-
- )
+
+ )
: {bio}
}
diff --git a/client/cms/src/stories/events/join-dialog.stories.tsx b/client/cms/src/stories/events/join-dialog.stories.tsx
index 5b53c14..82c25f7 100644
--- a/client/cms/src/stories/events/join-dialog.stories.tsx
+++ b/client/cms/src/stories/events/join-dialog.stories.tsx
@@ -22,5 +22,6 @@ export const Confirm: Story = {
args: {
event: exampleEvent,
onJoinEvent: () => { },
+ isPending: false,
},
};