Skip to content

Commit

Permalink
fix: router error
Browse files Browse the repository at this point in the history
  • Loading branch information
kcwww committed Nov 16, 2024
1 parent eec198f commit 910628f
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 145 deletions.
1 change: 1 addition & 0 deletions app/(protected)/main/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const getUserData = async () => {
const uuid = uuidv4();
const initUser: IUser = {
email: user.email,
uid: user.uid,
crystal_id: [],
uuid,
username: null,
Expand Down
146 changes: 146 additions & 0 deletions app/(protected)/nickname/_components/NicknameForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
'use client';

import { useState, useEffect } from 'react';

import { useRouter } from 'next/navigation';

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { toast } from 'sonner';

import { sessionUser } from '@/shared/types/user';
import { BACKEND_ROUTES, ROUTES } from '@/shared/constants/routes';
import clientComponentFetch from '@/shared/utils/fetch/clientComponentFetch';

import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import Link from 'next/link';
import { cn } from '@/lib/utils';

const formSchema = z.object({
username: z
.string()
.min(1, {
message: '유저 이름은 최소 1글자 이상이어야 합니다.',
})
.max(10, {
message: '유저 이름은 최대 10글자 이하여야 합니다.',
}),
});

const NicknameForm = ({ user }: { user: sessionUser }) => {
const [check, setCheck] = useState(false);
const [submit, setSubmit] = useState(false);
const router = useRouter();

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: '',
},
});

useEffect(() => {
return () => {
setCheck(false);
setSubmit(false);
};
}, []);

const onSubmit = async (values: z.infer<typeof formSchema>) => {
setSubmit(true);
const data = {
username: values.username,
email: user.email,
provider: user.provider,
};

try {
const response = await clientComponentFetch(BACKEND_ROUTES.NICKNAME, {
method: 'POST',
body: JSON.stringify(data),
});
if (response.ok) {
router.replace(ROUTES.MAKE);
router.refresh();
}
} catch (error) {
toast.error('유저 이름을 저장하는데 실패했습니다.');
setSubmit(false);
console.error(error);
}
};

const isLoading = form.formState.isSubmitting;

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-14">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem className="space-y-8">
<FormLabel className="text-xl text-white">
사용하실 이름을 입력해주세요
</FormLabel>
<FormControl>
<Input placeholder="Nickname" {...field} />
</FormControl>
<FormDescription>
이 이름은 다른 사용자들에게 보여지는 이름이 됩니다.
<br />
부적절한 닉네임은 서비스 이용에 제한이 있을 수 있습니다.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div className="flex items-center gap-8">
<Checkbox
className={cn(
'h-[1.8rem] w-[1.8rem] transform rounded-full text-white transition duration-200',
!check && 'bg-white'
)}
checked={check}
onCheckedChange={() => setCheck(!check)}
id="terms&policy"
/>
<Label className="text-white" htmlFor="terms&policy">
<Link
href="https://docs.myheratcrystal.com"
target="_blank"
className="hover:underline"
>
개인정보 처리방침 및 이용약관
</Link>
에 동의합니다.
</Label>
</div>

<Button
className="w-full"
variant={'secondary'}
type="submit"
disabled={isLoading || !check || submit}
>
저장하기
</Button>
</form>
</Form>
);
};

export default NicknameForm;
165 changes: 25 additions & 140 deletions app/(protected)/nickname/page.tsx
Original file line number Diff line number Diff line change
@@ -1,156 +1,41 @@
'use client';

import { useState, useEffect } from 'react';

import { useRouter } from 'next/navigation';
import { useSession } from 'next-auth/react';

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { sessionUser } from '@/shared/types/user';
import { BACKEND_ROUTES, ROUTES } from '@/shared/constants/routes';
import clientComponentFetch from '@/shared/utils/fetch/clientComponentFetch';
import { auth, signOut } from '@/auth';
import { Toaster } from 'sonner';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import Link from 'next/link';
import { cn } from '@/lib/utils';

const formSchema = z.object({
username: z
.string()
.min(1, {
message: '유저 이름은 최소 1글자 이상이어야 합니다.',
})
.max(10, {
message: '유저 이름은 최대 10글자 이하여야 합니다.',
}),
});

const Nickname = () => {
const { data: session } = useSession();
const [check, setCheck] = useState(false);
const [submit, setSubmit] = useState(false);

const router = useRouter();
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: '',
},
});

useEffect(() => {
if (!session) {
router.replace(ROUTES.LANDING);
}

return () => {
setCheck(false);
setSubmit(false);
};
}, []);

const onSubmit = async (values: z.infer<typeof formSchema>) => {
setSubmit(true);
const user = session?.user as sessionUser;
const data = {
username: values.username,
import NicknameForm from '@/app/(protected)/nickname/_components/NicknameForm';
import { sessionUser, User as UserType } from '@/shared/types/user';
import { redirect } from 'next/navigation';
import { ROUTES } from '@/shared/constants/routes';
import User from '@/shared/database/mongodb/models/userModel';
import { connectToMongoDB } from '@/shared/database/mongodb/config';

const Nickname = async () => {
const session = await auth();
if (!session) return redirect(ROUTES.LANDING);

const user = session.user as sessionUser;
await connectToMongoDB();
const result = (
await User.findOne({
email: user.email,
uid: user.uid,
provider: user.provider,
};
})
)?.toObject() as UserType;

try {
const response = await clientComponentFetch(BACKEND_ROUTES.NICKNAME, {
method: 'POST',
body: JSON.stringify(data),
});
if (response.ok) {
router.replace(ROUTES.MAKE);
}
} catch (error) {
toast.error('유저 이름을 저장하는데 실패했습니다.');
setSubmit(false);
console.error(error);
}
};
if (!result) {
signOut();
redirect(ROUTES.LANDING);
}

const isLoading = form.formState.isSubmitting;
if (result.username !== null) redirect(ROUTES.MAIN);

return (
<>
<section className="flex h-dvh flex-col items-center justify-between py-28">
<h1 className="text-3xl font-bold text-yellow-300">
수정 구슬 속 내 마음
</h1>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-14">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem className="space-y-8">
<FormLabel className="text-xl text-white">
사용하실 이름을 입력해주세요
</FormLabel>
<FormControl>
<Input placeholder="Nickname" {...field} />
</FormControl>
<FormDescription>
이 이름은 다른 사용자들에게 보여지는 이름이 됩니다.
<br />
부적절한 닉네임은 서비스 이용에 제한이 있을 수 있습니다.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div className="flex items-center gap-8">
<Checkbox
className={cn(
'h-[1.8rem] w-[1.8rem] transform rounded-full text-white transition duration-200',
!check && 'bg-white'
)}
checked={check}
onCheckedChange={() => setCheck(!check)}
id="terms&policy"
/>
<Label className="text-white" htmlFor="terms&policy">
<Link
href="https://docs.myheratcrystal.com"
target="_blank"
className="hover:underline"
>
개인정보 처리방침 및 이용약관
</Link>
에 동의합니다.
</Label>
</div>

<Button
className="w-full"
variant={'secondary'}
type="submit"
disabled={isLoading || !check || submit}
>
저장하기
</Button>
</form>
</Form>
<NicknameForm user={user} />
<div />
</section>
<Toaster richColors />
Expand Down
2 changes: 1 addition & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ html::-webkit-scrollbar {
}

.ui-section {
@apply pointer-events-none relative flex min-h-svh w-full flex-col items-center justify-between overflow-hidden px-10 pb-20 pt-10;
@apply pointer-events-none relative flex min-h-dvh w-full flex-col items-center justify-between overflow-hidden px-10 pb-20 pt-10;
z-index: 1;
}

Expand Down
3 changes: 1 addition & 2 deletions auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ export const { auth, handlers, signIn, signOut, unstable_update } = NextAuth({
},

session: async ({ session, token }: any) => {
session.user.name = token.id;
session.user.uid = token.id;
session.user.provider = token.provider;

return session;
},
},
Expand Down
4 changes: 3 additions & 1 deletion shared/database/mongodb/models/userModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Crystal from '@/shared/database/mongodb/models/crystalModel';
export interface IUser {
email: string;
uuid: string;
uid: string;
crystal_id: mongoose.Schema.Types.ObjectId[] | string[] | [];
username: string | null;
provider: string;
Expand All @@ -19,6 +20,7 @@ export interface IUserDocument extends IUser, Document {
const userSchema = new mongoose.Schema<IUserDocument>(
{
email: { type: String, required: true },
uid: { type: String, required: true },
uuid: { type: String, required: true },
crystal_id: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Crystal' }],
username: { type: String, default: null },
Expand All @@ -30,7 +32,7 @@ const userSchema = new mongoose.Schema<IUserDocument>(
);

// 복합 인덱스 생성
userSchema.index({ email: 1, provider: 1 }, { unique: true });
userSchema.index({ email: 1, provider: 1, uid: 1 }, { unique: true });

// User 모델의 프리 훅을 사용하여 관련 Crystal 및 Message 모두 삭제
userSchema.pre('findOneAndDelete', async function (next) {
Expand Down
2 changes: 1 addition & 1 deletion shared/types/user.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type User = {
} & IUser;

export type sessionUser = {
name: string;
uid: string;
provider: string;
email: string;
};

0 comments on commit 910628f

Please sign in to comment.