Skip to content

Commit 287be4e

Browse files
committed
feat: wiring get user profile
1 parent 6491854 commit 287be4e

7 files changed

Lines changed: 107 additions & 19 deletions

File tree

src/domains/Profile.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { z } from "zod";
22

3-
export const UserSchema = z.object({
3+
export const profileResSchema = z.object({
44
id: z.number(),
55
username: z.string(),
66
email: z.string(),
@@ -14,21 +14,23 @@ export const UserSchema = z.object({
1414
github: z.string(),
1515
linkedin: z.string(),
1616
personal_web: z.string(),
17-
created_at: z.string(),
18-
updated_at: z.string(),
17+
created_at: z.date(),
18+
updated_at: z.date(),
1919
});
2020

21-
export type UserType = z.infer<typeof UserSchema>;
21+
export type ProfileResType = z.infer<typeof profileResSchema>;
2222

23-
export const profileFormSchema = z.object({
24-
fullname: z.string().min(1, "Fullname is required"),
25-
date_of_birth: z.string().min(1, "Date of birth is required"),
26-
gender: z.enum(["Male", "Female"], { required_error: "Please select a gender" }),
27-
phone_number: z.string().min(1, "Phone number is required"),
28-
address: z.string().min(1, "Address is required"),
29-
github: z.string().url("Please enter a valid GitHub URL").optional().or(z.literal("")),
30-
linkedin: z.string().url("Please enter a valid LinkedIn URL").optional().or(z.literal("")),
31-
personal_web: z.string().url("Please enter a valid personal website URL").optional().or(z.literal("")),
32-
});
23+
export const createProfileFormSchema = (t: (key: string) => string) =>
24+
z.object({
25+
username: z.string().min(1, t("Profile.validation.username-required")),
26+
fullname: z.string().min(1, t("Profile.validation.fullname-required")),
27+
date_of_birth: z.string().min(1, t("Profile.validation.date-of-birth-required")),
28+
gender: z.enum(["Male", "Female"], { required_error: t("Profile.validation.gender-required") }),
29+
phone_number: z.string().min(1, t("Profile.validation.phone-number-required")),
30+
address: z.string().min(1, t("Profile.validation.address-required")),
31+
github: z.string().url(t("Profile.validation.github-invalid-url")).optional().or(z.literal("")),
32+
linkedin: z.string().url(t("Profile.validation.linkedin-invalid-url")).optional().or(z.literal("")),
33+
personal_web: z.string().url(t("Profile.validation.personal-web-invalid-url")).optional().or(z.literal("")),
34+
});
3335

34-
export type ProfileFormType = z.infer<typeof profileFormSchema>;
36+
export type ProfileFormType = z.infer<ReturnType<typeof createProfileFormSchema>>;

src/features/profile/components/ProfileForm.tsx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,32 @@ import { useForm } from "react-hook-form";
33
import { zodResolver } from "@hookform/resolvers/zod";
44
import { format } from "date-fns";
55
import { CalendarIcon } from "lucide-react";
6+
import { useTranslations } from "next-intl";
67
import { Button } from "@/components/ui/Button";
78
import { Input } from "@/components/ui/Input";
89
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/Select";
910
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/Form";
1011
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/Popover";
1112
import { Calendar } from "@/components/ui/Calendar";
12-
import { profileFormSchema, ProfileFormType } from "@/domains/Profile";
13+
import { createProfileFormSchema, ProfileFormType } from "@/domains/Profile";
1314
import { cn } from "@/lib/utils";
15+
import { useGetProfile } from "../hooks";
16+
import Loader from "@/components/common/Loader";
17+
import { useEffect } from "react";
1418

1519
interface ProfileFormProps {
1620
activeTab: "account" | "information";
1721
}
1822

1923
const ProfileForm = ({ activeTab }: ProfileFormProps) => {
24+
const t = useTranslations();
25+
const profileFormSchema = createProfileFormSchema(t);
26+
const { data, isLoading } = useGetProfile();
27+
2028
const form = useForm<ProfileFormType>({
2129
resolver: zodResolver(profileFormSchema),
2230
defaultValues: {
31+
username: "",
2332
fullname: "",
2433
date_of_birth: "",
2534
phone_number: "",
@@ -30,15 +39,49 @@ const ProfileForm = ({ activeTab }: ProfileFormProps) => {
3039
},
3140
});
3241

42+
useEffect(() => {
43+
if (data) {
44+
form.reset({
45+
username: data.username || "",
46+
fullname: data.fullname || "",
47+
date_of_birth: data.date_of_birth || "",
48+
phone_number: data.phone_number || "",
49+
address: data.address || "",
50+
github: data.github || "",
51+
linkedin: data.linkedin || "",
52+
personal_web: data.personal_web || "",
53+
});
54+
}
55+
}, [data]);
56+
3357
const onSubmit = (data: ProfileFormType) => {
3458
// ! TODO handle query mutation
3559
console.log("Profile data:", data);
3660
};
3761

62+
console.log("dataaa", data);
63+
if (isLoading) {
64+
return <Loader />;
65+
}
66+
3867
const renderForm = () => {
3968
if (activeTab === "account") {
4069
return (
4170
<>
71+
<FormField
72+
control={form.control}
73+
name="username"
74+
render={({ field }) => (
75+
<FormItem>
76+
<FormLabel>Username</FormLabel>
77+
<FormControl>
78+
<Input placeholder="Enter your username" {...field} />
79+
</FormControl>
80+
<FormMessage />
81+
</FormItem>
82+
)}
83+
/>
84+
4285
<FormField
4386
control={form.control}
4487
name="fullname"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as useGetProfile } from "./useGetProfile";
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { profileService } from "@/services/profile";
2+
import { useQuery } from "@tanstack/react-query";
3+
4+
const useGetProfile = () =>
5+
useQuery({
6+
queryKey: ["getProfile"],
7+
queryFn: async () => {
8+
const response = await profileService.getProfile();
9+
return response.data;
10+
},
11+
});
12+
13+
export default useGetProfile;

src/locales/en.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,5 +232,18 @@
232232
"title": "My Blogs",
233233
"description": "List of post and blog article",
234234
"not-found": "No blogs found."
235+
},
236+
"Profile": {
237+
"validation": {
238+
"username-required": "Nama Panggilan wajib diisi",
239+
"fullname-required": "Fullname is required",
240+
"date-of-birth-required": "Date of birth is required",
241+
"gender-required": "Please select a gender",
242+
"phone-number-required": "Phone number is required",
243+
"address-required": "Address is required",
244+
"github-invalid-url": "Please enter a valid GitHub URL",
245+
"linkedin-invalid-url": "Please enter a valid LinkedIn URL",
246+
"personal-web-invalid-url": "Please enter a valid personal website URL"
247+
}
235248
}
236249
}

src/locales/id.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,5 +232,18 @@
232232
"title": "Blog Saya",
233233
"description": "Daftar postingan dan artikel blog",
234234
"not-found": "Tidak ada blog yang ditemukan."
235+
},
236+
"Profile": {
237+
"validation": {
238+
"username-required": "Nama Panggilan wajib diisi",
239+
"fullname-required": "Nama lengkap wajib diisi",
240+
"date-of-birth-required": "Tanggal lahir wajib diisi",
241+
"gender-required": "Silakan pilih jenis kelamin",
242+
"phone-number-required": "Nomor telepon wajib diisi",
243+
"address-required": "Alamat wajib diisi",
244+
"github-invalid-url": "Silakan masukkan URL GitHub yang valid",
245+
"linkedin-invalid-url": "Silakan masukkan URL LinkedIn yang valid",
246+
"personal-web-invalid-url": "Silakan masukkan URL website pribadi yang valid"
247+
}
235248
}
236249
}

src/services/profile/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { HttpResponse } from "@/types/http";
22
import { fetcher } from "../instance";
3-
import { UserType } from "@/domains/Profile";
3+
import { ProfileResType } from "@/domains/Profile";
44

55
export const profileService = {
6-
getUserId: async (): Promise<HttpResponse<UserType>> => {
7-
return fetcher.get("user");
6+
/**
7+
* API to get detail profile user
8+
*/
9+
getProfile: async (): Promise<HttpResponse<ProfileResType>> => {
10+
return fetcher.get("/user");
811
},
912
};

0 commit comments

Comments
 (0)