diff --git a/atlas/migrations/20241126073229_add_column_users_email.sql b/atlas/migrations/20241126073229_add_column_users_email.sql new file mode 100644 index 00000000..b4f96fdd --- /dev/null +++ b/atlas/migrations/20241126073229_add_column_users_email.sql @@ -0,0 +1,2 @@ +-- Modify "users" table +ALTER TABLE "public"."users" ADD COLUMN "email" character varying(255) NULL, ADD COLUMN "email_verified" boolean NULL DEFAULT false; diff --git a/atlas/migrations/20241126073311_change_user_email_not_null.sql b/atlas/migrations/20241126073311_change_user_email_not_null.sql new file mode 100644 index 00000000..3f4e82ef --- /dev/null +++ b/atlas/migrations/20241126073311_change_user_email_not_null.sql @@ -0,0 +1,4 @@ +-- Modify "users" table +ALTER TABLE "public"."users" ALTER COLUMN "email" SET NOT NULL, ALTER COLUMN "email_verified" SET NOT NULL; +-- Create index "email" to table: "users" +CREATE UNIQUE INDEX "email" ON "public"."users" ("email"); diff --git a/atlas/migrations/atlas.sum b/atlas/migrations/atlas.sum index 82ff314c..0a1d2f5e 100644 --- a/atlas/migrations/atlas.sum +++ b/atlas/migrations/atlas.sum @@ -1,6 +1,8 @@ -h1:33BOoFIDyYBMfpcF5tQDv+RBNRH0fTenBPHUnlnSCaI= +h1:5aYCq2wr+qJ4ckP53Fj+f/l0JFFOQG7C9ictTx6NvPo= 20241021163015_create_user.sql h1:gCgeqsR5gC7HN2P2UeGrpMNAW5b9zJNSwPtURtwws1A= 20241021163211_create_client.sql h1:Zk3Nd8qUAnS7v7eIvNaADHK8D0RqIcpkCjUT/Guxt1o= 20241021163446_create_redirect_uri.sql h1:K1C6Q4XOQKbChyejJ/M7F3JHVOgu6DTweXnnX/fOjJ0= 20241024084524_create_approvals.sql h1:7ar7WTyOGflX99Dpm5JiiCInKNrvPk+3UM6yHC+o4Sw= 20241112154715_create_auth_codes.sql h1:GV/eitiRSfHDM1t1YDxKNKsNsrv35QPNSXDZPPKA+Ns= +20241126073229_add_column_users_email.sql h1:st3u0Yl/fpXgr3JHyeT2/PHo5gywJY7lxm5l12Wd7u8= +20241126073311_change_user_email_not_null.sql h1:crChtzneQLh7UXWKfEezju1d8/mAK+JzzfFgOHkq6MM= diff --git a/atlas/schema.hcl b/atlas/schema.hcl index ac40a22d..02a63475 100644 --- a/atlas/schema.hcl +++ b/atlas/schema.hcl @@ -5,6 +5,13 @@ table "users" { column "id" { type = bigserial } + column "email" { + type = varchar(255) + } + column "email_verified" { + type = boolean + default = false + } column "name" { type = varchar(255) } @@ -24,6 +31,10 @@ table "users" { columns = [column.name] unique = true } + index "email" { + columns = [column.email] + unique = true + } } table "clients" { schema = schema.public diff --git a/frontend/src/app/member/page.tsx b/frontend/src/app/member/page.tsx index 030c1230..85e42048 100644 --- a/frontend/src/app/member/page.tsx +++ b/frontend/src/app/member/page.tsx @@ -14,8 +14,26 @@ export default function Page() { return ( *': { margin: 2 } }}> - ダッシュボード - {user.name} + ダッシュボード + + + + Account + + + + + ID: {user.id} + + + Name: {user.name} + + + Email: {user.email} + + + diff --git a/frontend/src/components/SignupForm.tsx b/frontend/src/components/SignupForm.tsx index 96f37800..b3c87d4e 100644 --- a/frontend/src/components/SignupForm.tsx +++ b/frontend/src/components/SignupForm.tsx @@ -9,6 +9,7 @@ import { Controller, useForm } from 'react-hook-form' type SignupInput = { name: string + email: string password: string passwordConfirmation: string } @@ -20,13 +21,19 @@ export const SignupForm = ({ next }: SignupFormProps): JSX.Element => { const router = useRouter() const query = useSearchParams() const { control, handleSubmit, setError } = useForm({ - defaultValues: { name: '', password: '', passwordConfirmation: '' }, + defaultValues: { + name: '', + email: '', + password: '', + passwordConfirmation: '', + }, }) const submit = useCallback( async (data: SignupInput) => { const { error } = await client.POST('/users/signup', { body: { name: data.name, + email: data.email, password: data.password, password_confirmation: data.passwordConfirmation, }, @@ -34,6 +41,11 @@ export const SignupForm = ({ next }: SignupFormProps): JSX.Element => { if (!!error) { if (error.error === 'name_already_used') { setError('name', { message: error.error }) + } else if ( + error.error === 'email_already_used' || + error.error === 'email_format_invalid' + ) { + setError('email', { message: error.error_description }) } else if (error.error === 'password_length_not_enough') { setError('password', { message: error.error_description }) } else if (error.error === 'password_confirmation_not_match') { @@ -76,6 +88,23 @@ export const SignupForm = ({ next }: SignupFormProps): JSX.Element => { )} /> + + ( + + )} + /> +