Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ FROM node:20.15.0-alpine AS base
ARG NEXT_PUBLIC_LIFF_ID=""
ARG NEXT_PUBLIC_TARGET_DATE=01-15-2025
ARG NODE_ENV=production
ARG NEXT_PUBLIC_BASE_URL

ENV NEXT_PUBLIC_LIFF_ID=${NEXT_PUBLIC_LIFF_ID}
ENV NEXT_PUBLIC_TARGET_DATE=${NEXT_PUBLIC_TARGET_DATE}
ENV NODE_ENV=${NODE_ENV}
ENV NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}

FROM base AS deps
WORKDIR /app
Expand Down
188 changes: 137 additions & 51 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-slot": "^1.1.1",
"@tanstack/react-query": "^5.64.2",
"axios": "^1.7.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
Expand All @@ -31,6 +33,7 @@
"react-day-picker": "^8.10.1",
"react-dom": "^18.2.0",
"react-hook-form": "^7.54.2",
"react-hot-toast": "^2.5.1",
"react-qr-code": "^2.0.15",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
181 changes: 111 additions & 70 deletions src/app/(user)/edit/_components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,122 +3,163 @@
import { useEffect } from 'react';

import TextInput from '../../register/_components/textInput';
import ErrorMsg from '../../register/_components/errorMsg';
import DropdownInput from '../../register/_components/dropdownInput';
import ComboBox from '../../register/_components/comboBox';
import Label from '../../register/_components/label';
import DateInput from '../../register/_components/dateInput';
import { Button } from '@/components/ui/button';

import { SubmitHandler, useForm } from 'react-hook-form';
import { User, UserSchema } from '../schema/user';
import { universities } from '../../register/_data/universities';
import { faculties } from '../../register/_data/faculties';
import { studies } from '../../register/_data/studies';
import { sizes } from '../../register/_data/size';
import { ErrorMsg, ErrorMsgFloat } from '../../register/_components/errorMsg';
import Image from 'next/image';

import { zodResolver } from '@hookform/resolvers/zod';
import { sizeJersey } from '@/const/size';
import { faculties } from '@/const/faculties';
import { EditForm, EditSchema } from '@/schema/edit';
import { educationsMap } from '@/const/educations';
import { universities } from '@/const/universities';
import { statusMap } from '@/const/status';

import { SubmitHandler, useForm } from 'react-hook-form';
import { useAuth } from '@/contexts/auth';
import { useLiff } from '@/contexts/liff';
import toast from 'react-hot-toast';

export default function Form() {
const { editError, edit, isEditing, user: defaultUser } = useAuth();
const { client } = useLiff();
const {
handleSubmit,
register,
setValue,
watch,
reset,
formState: { errors },
} = useForm<User>({
resolver: zodResolver(UserSchema),
} = useForm<EditForm>({
resolver: zodResolver(EditSchema),
});
useEffect(() => {
if (defaultUser) {
reset({
name: defaultUser.name,
email: defaultUser.email,
phone: defaultUser.phone,
education: defaultUser.education,
university: defaultUser.university,
status: defaultUser.status,
graduatedYear: defaultUser.graduatedYear,
faculty: defaultUser.faculty,
age: defaultUser.age,
sizeJersey: defaultUser.sizeJersey,
foodLimitation: defaultUser.foodLimitation,
chronicDisease: defaultUser.chronicDisease,
drugAllergy: defaultUser.drugAllergy,
});
}
}, [defaultUser, reset]);

const user = watch();

const onSubmit: SubmitHandler<User> = data => {
console.log(data);
const onSubmit: SubmitHandler<EditForm> = async data => {
const context = client?.getContext();
const userId = context?.userId;
if (!userId) {
const error = new Error('Failed edit: userId is undefined');
console.error(error);
return;
}

const toastId = toast.loading('รอสักครู่');
const resp = await edit({ ...data, id: userId });
if (resp.success) {
toast.success('บันทึกการแก้ไขสำเร็จ');
} else {
toast.error('บันทึกการแก้ไขไม่สำเร็จ');
}

toast.dismiss(toastId);
};

const updateField = (field: keyof User) => {
return (value: User[keyof User]) => {
const updateField = (field: keyof EditForm) => {
return (value: EditForm[keyof EditForm]) => {
setValue(field, value);
};
};

useEffect(() => {
let status: User['status'];
let status: EditForm['status'];

// set default value
if (
!!user.study &&
!!user.education &&
!!user.university &&
(user.study != 'จบการศึกษาแล้ว' ||
(user.education != 'graduated' ||
user.university != 'จุฬาลงกรณ์มหาวิทยาลัย')
) {
setValue('graduateYear', '9999');
setValue('graduateFaculty', 'ไม่ระบุ');
setValue('graduatedYear', '9999');
setValue('faculty', 'ไม่ระบุ');
}

// set status
if (user.study == 'กำลังศึกษาอยู่') {
if (user.education == 'studying') {
if (user.university == 'จุฬาลงกรณ์มหาวิทยาลัย') {
status = 'นิสิตปัจจุบัน';
status = 'chula_student';
} else {
status = 'นักศึกษา';
status = 'general_student';
}
} else {
if (user.university == 'จุฬาลงกรณ์มหาวิทยาลัย') {
status = 'นิสิตเก่า';
status = 'alumni';
} else {
status = 'บุคคลทั่วไป';
status = 'general_public';
}
}

setValue('status', status);
}, [user.study, user.university, setValue]);
}, [user.education, user.university, setValue]);

return (
<div className="w-full flex-1 bg-white">
<form
className="w-full space-y-4 px-6 py-8"
onSubmit={handleSubmit(onSubmit)}
>
{/* fullname */}
{/* name */}
<div className="relative space-y-1">
<Label isRequired>ชื่อ-นามสกุล (ไม่มีคำนำหน้า)</Label>
<TextInput {...register('fullname')} />
<ErrorMsg message={errors.fullname?.message} />
<TextInput {...register('name')} />
<ErrorMsgFloat>{errors.name?.message}</ErrorMsgFloat>
</div>

{/* email */}
<div className="relative space-y-1">
<Label isRequired>อีเมล</Label>
<TextInput {...register('email')} />
<ErrorMsg message={errors.email?.message} />
<ErrorMsgFloat>{errors.email?.message}</ErrorMsgFloat>
</div>

{/* tel */}
{/* phone */}
<div className="relative space-y-1">
<Label isRequired>หมายเลขโทรศัพท์</Label>
<TextInput {...register('tel')} />
<ErrorMsg message={errors.tel?.message} />
<TextInput {...register('phone')} />
<ErrorMsgFloat>{errors.phone?.message}</ErrorMsgFloat>
</div>

{/* study */}
{/* education */}
<div className="relative space-y-1">
<Label isRequired>การศึกษา</Label>
<DropdownInput
value={user.study}
setValue={updateField('study')}
value={educationsMap[user.education]}
setValue={val => setValue('education', educationsMap[val])}
placeholder="กำลังศึกษาอยู่"
choices={[...studies]}
choices={Object.keys(educationsMap).map(key => key)}
/>
<ErrorMsg message={errors.study?.message} />
<ErrorMsgFloat>{errors.education?.message}</ErrorMsgFloat>
</div>

{/* university */}
{/* TODO: optimize here, there are 390 universties in list */}
{user.study && (
{user.education && (
<div className="relative space-y-1">
<Label isRequired>
{user.study == 'กำลังศึกษาอยู่'
{user.education == 'studying'
? 'มหาวิทยาลัย'
: 'มหาวิทยาลัยที่จบการศึกษา'}
</Label>
Expand All @@ -130,26 +171,26 @@ export default function Form() {
searchText="ค้นหามหาวิทยาลัย"
emptyText="ไม่มีข้อมูล"
/>
<ErrorMsg message={errors.university?.message} />
<ErrorMsgFloat>{errors.university?.message}</ErrorMsgFloat>
</div>
)}

{/* status */}
<div className="relative space-y-1">
<Label isRequired>สถานะ</Label>
<TextInput value={user.status || ''} readOnly />
<ErrorMsg message={errors.status?.message} />
<TextInput value={statusMap[user.status] || ''} readOnly />
<ErrorMsgFloat>{errors.status?.message}</ErrorMsgFloat>
</div>

{/* graduate year && graduate faculty*/}
{user.study == 'จบการศึกษาแล้ว' &&
{user.education == 'graduated' &&
user.university == 'จุฬาลงกรณ์มหาวิทยาลัย' && (
<div className="flex justify-between gap-4">
<div className="relative w-1/2 space-y-2">
<Label isRequired>ปีที่สำเร็จการศึกษา</Label>
<ComboBox
value={user.graduateYear}
setValue={updateField('graduateYear')}
value={user.graduatedYear}
setValue={updateField('graduatedYear')}
placeholder="2544"
emptyText="ไม่มีข้อมูล"
searchText="ค้นหาปีที่สำเร็จการศึกษา"
Expand All @@ -160,70 +201,69 @@ export default function Form() {
(_, i) => (2468 + i).toString(),
)}
/>
<ErrorMsg message={errors.graduateYear?.message} />
<ErrorMsgFloat>{errors.graduatedYear?.message}</ErrorMsgFloat>
</div>

<div className="relative w-1/2 space-y-2">
<Label isRequired>คณะที่สำเร็จการศึกษา</Label>
<ComboBox
value={user.graduateFaculty}
setValue={updateField('graduateFaculty')}
value={user.faculty}
setValue={updateField('faculty')}
placeholder="กรุณาเลือก"
emptyText="ไม่มีข้อมูล"
searchText="ค้นหาคณะที่สำเร็จการศึกษา"
choices={[...faculties]}
/>
<ErrorMsg message={errors.graduateFaculty?.message} />
<ErrorMsgFloat>{errors.faculty?.message}</ErrorMsgFloat>
</div>
</div>
)}

{/* birthDate */}
<div className="relative space-y-1">
<Label isRequired>วันเกิด</Label>
<DateInput
value={user.birthdate}
setValue={updateField('birthdate')}
/>
<ErrorMsg message={errors.birthdate?.message} />
<Label isRequired>อายุ</Label>
<TextInput {...register('age')} />
<ErrorMsgFloat>{errors.age?.message}</ErrorMsgFloat>
</div>

{/* size */}
<div className="relative space-y-1">
<Label isRequired>ขนาดเสื้อ</Label>
<DropdownInput
value={user.size}
setValue={updateField('size')}
value={user.sizeJersey}
setValue={updateField('sizeJersey')}
placeholder="กรุณาเลือก"
choices={[...sizes]}
choices={[...sizeJersey]}
/>
<ErrorMsg message={errors.size?.message} />
<ErrorMsgFloat>{errors.sizeJersey?.message}</ErrorMsgFloat>
</div>

{/* foodAllegy */}
<div className="relative space-y-1">
<Label>ข้อจำกัดด้านอาหาร</Label>
<TextInput {...register('foodAllegy')} />
<ErrorMsg message={errors.foodAllegy?.message} />
<TextInput {...register('foodLimitation')} />
<ErrorMsgFloat>{errors.foodLimitation?.message}</ErrorMsgFloat>
</div>

{/* disease */}
<div className="relative space-y-1">
<Label>โรคประจำตัว</Label>
<TextInput {...register('disease')} />
<ErrorMsg message={errors.disease?.message} />
<TextInput {...register('chronicDisease')} />
<ErrorMsgFloat>{errors.chronicDisease?.message}</ErrorMsgFloat>
</div>

{/* drugAllegy */}
<div className="relative space-y-1">
<Label>การแพ้ยา</Label>
<TextInput {...register('drugAllegy')} />
<ErrorMsg message={errors.drugAllegy?.message} />
<TextInput {...register('drugAllergy')} />
<ErrorMsgFloat>{errors.drugAllergy?.message}</ErrorMsgFloat>
</div>

{/* submit */}
<div className="flex justify-center pt-4">
<Button className="flex items-center justify-center gap-2 px-16 text-lg">
<div className="flex flex-col items-center justify-center gap-2 pt-4">
<Button
className="flex items-center justify-center gap-2 px-16 text-lg"
disabled={isEditing}
>
<Image
src={'/user/profile/save-icon.svg'}
alt="save-icon"
Expand All @@ -232,6 +272,7 @@ export default function Form() {
/>
<input type="submit" value={'บันทึกการแก้ไข'} />
</Button>
<ErrorMsg className="text-base">{editError?.message}</ErrorMsg>
</div>
</form>
</div>
Expand Down
Loading
Loading