Skip to content

Commit 6f2ed04

Browse files
committed
Before Calendar and availability
1 parent 8eee667 commit 6f2ed04

File tree

14 files changed

+258
-12
lines changed

14 files changed

+258
-12
lines changed

.eslintrc.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
"extends": [
33
"@rocketseat/eslint-config/react",
44
"next/core-web-vitals"
5-
]
5+
],
6+
"rules": {
7+
"camelcase": "off"
8+
}
69
}

prisma/dev.db

8 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- CreateTable
2+
CREATE TABLE "user_time_intervals" (
3+
"id" TEXT NOT NULL PRIMARY KEY,
4+
"week_day" INTEGER NOT NULL,
5+
"time_start_in_minutes" INTEGER NOT NULL,
6+
"time_end_in_minutes" INTEGER NOT NULL,
7+
"user_id" TEXT NOT NULL,
8+
CONSTRAINT "user_time_intervals_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
9+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "users" ADD COLUMN "bio" TEXT;

prisma/schema.prisma

+16-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ model User {
1414
id String @id @default(uuid())
1515
username String @unique
1616
name String
17+
bio String?
1718
email String? @unique
1819
avatar_url String?
1920
created_at DateTime @default(now())
2021
21-
accounts Account[]
22-
sessions Session[]
22+
accounts Account[]
23+
sessions Session[]
24+
timeIntervals UserTimeInterval[]
2325
2426
@@map("users")
2527
}
@@ -53,3 +55,15 @@ model Session {
5355
5456
@@map("sessions")
5557
}
58+
59+
model UserTimeInterval {
60+
id String @id @default(uuid())
61+
week_day Int
62+
time_start_in_minutes Int
63+
time_end_in_minutes Int
64+
65+
user User @relation(fields: [user_id], references: [id])
66+
user_id String
67+
68+
@@map("user_time_intervals")
69+
}

src/@types/next-auth.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ declare module 'next-auth' {
88
username: string
99
avatar_url: string
1010
}
11+
12+
interface Session {
13+
user: User
14+
}
1115
}

src/lib/auth/prisma-adapter.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Adapter } from 'next-auth/adapters'
22
import { prisma } from '../prisma'
3-
import { NextApiRequest, NextApiResponse } from 'next'
3+
import { NextApiRequest, NextApiResponse, NextPageContext } from 'next'
44
import { parseCookies, destroyCookie } from 'nookies'
55

66
export function PrismaAdapter(
7-
req: NextApiRequest,
8-
res: NextApiResponse,
7+
req: NextApiRequest | NextPageContext['req'],
8+
res: NextApiResponse | NextPageContext['res'],
99
): Adapter {
1010
return {
1111
async createUser(user) {

src/pages/api/auth/[...nextauth].api.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { PrismaAdapter } from '@/lib/auth/prisma-adapter'
2-
import { NextApiRequest, NextApiResponse } from 'next'
2+
import { NextApiRequest, NextApiResponse, NextPageContext } from 'next'
33
import NextAuth, { NextAuthOptions } from 'next-auth'
44
import GoogleProvider, { GoogleProfile } from 'next-auth/providers/google'
55

66
export function buildNextAuthOptions(
7-
req: NextApiRequest,
8-
res: NextApiResponse,
7+
req: NextApiRequest | NextPageContext['req'],
8+
res: NextApiResponse | NextPageContext['res'],
99
): NextAuthOptions {
1010
return {
1111
adapter: PrismaAdapter(req, res),

src/pages/api/users/profile.api.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { NextApiRequest, NextApiResponse } from 'next'
2+
import { getServerSession } from 'next-auth'
3+
import { buildNextAuthOptions } from '../auth/[...nextauth].api'
4+
import { z } from 'zod'
5+
import { prisma } from '@/lib/prisma'
6+
7+
const updateProfileBodySchema = z.object({
8+
bio: z.string(),
9+
})
10+
11+
export default async function hadler(
12+
req: NextApiRequest,
13+
res: NextApiResponse,
14+
) {
15+
if (req.method !== 'PUT') {
16+
return res.status(405).end()
17+
}
18+
const session = await getServerSession(
19+
req,
20+
res,
21+
buildNextAuthOptions(req, res),
22+
)
23+
24+
if (!session) {
25+
return res.status(401).end()
26+
}
27+
28+
const { bio } = updateProfileBodySchema.parse(req.body)
29+
30+
await prisma.user.update({
31+
where: {
32+
id: session.user.id,
33+
},
34+
data: {
35+
bio,
36+
},
37+
})
38+
39+
return res.status(204).end()
40+
}
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { NextApiRequest, NextApiResponse } from 'next'
2+
import { getServerSession } from 'next-auth'
3+
import { buildNextAuthOptions } from '../auth/[...nextauth].api'
4+
import { z } from 'zod'
5+
import { prisma } from '@/lib/prisma'
6+
7+
const timeIntervalsBodySchema = z.object({
8+
intervals: z.array(
9+
z.object({
10+
weekDay: z.number(),
11+
startTimeInMinutes: z.number(),
12+
endTimeInMinutes: z.number(),
13+
}),
14+
),
15+
})
16+
17+
export default async function hadler(
18+
req: NextApiRequest,
19+
res: NextApiResponse,
20+
) {
21+
if (req.method !== 'POST') {
22+
return res.status(405).end()
23+
}
24+
const session = await getServerSession(
25+
req,
26+
res,
27+
buildNextAuthOptions(req, res),
28+
)
29+
30+
if (!session) {
31+
return res.status(401).end()
32+
}
33+
34+
const { intervals } = timeIntervalsBodySchema.parse(req.body)
35+
36+
await Promise.all(
37+
intervals.map((interval) => {
38+
return prisma.userTimeInterval.create({
39+
data: {
40+
week_day: interval.weekDay,
41+
time_start_in_minutes: interval.startTimeInMinutes,
42+
time_end_in_minutes: interval.endTimeInMinutes,
43+
user_id: session.user?.id,
44+
},
45+
})
46+
}),
47+
)
48+
49+
return res.json({
50+
session,
51+
})
52+
}

src/pages/register/connect-calendar/index.page.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export default function ConnectCalendar() {
1616
await signIn('google')
1717
}
1818

19+
async function handleNavigateToNextStep() {
20+
await router.push('/register/time-intervals')
21+
}
22+
1923
return (
2024
<Container>
2125
<Header>
@@ -53,7 +57,11 @@ export default function ConnectCalendar() {
5357
</AuthError>
5458
)}
5559

56-
<Button type="submit" disabled={!isSignedIn}>
60+
<Button
61+
onClick={handleNavigateToNextStep}
62+
type="submit"
63+
disabled={!isSignedIn}
64+
>
5765
Próximo passo
5866
<ArrowRight />
5967
</Button>

src/pages/register/time-intervals/index.page.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { z } from 'zod'
2121
import { getWeekDays } from '@/utils/get-week-days'
2222
import { zodResolver } from '@hookform/resolvers/zod'
2323
import { convertTimeStringToMinutes } from '@/utils/convert-time-in-minutes'
24+
import { api } from '@/lib/axios'
25+
import { useRouter } from 'next/router'
2426

2527
const timeIntervalsFormSchema = z.object({
2628
intervals: z
@@ -85,6 +87,8 @@ export default function TimeIntervals() {
8587
},
8688
})
8789

90+
const router = useRouter()
91+
8892
const weekDays = getWeekDays()
8993

9094
const { fields } = useFieldArray({
@@ -94,8 +98,11 @@ export default function TimeIntervals() {
9498

9599
const intervals = watch('intervals')
96100

97-
async function handleSetTimeIntervals(data: TimeIntervalsFormOutput) {
98-
console.log(data)
101+
async function handleSetTimeIntervals(data: any) {
102+
const { intervals } = data as TimeIntervalsFormOutput
103+
await api.post('users/time-intervals', { intervals })
104+
105+
await router.push('/register/update-profile')
99106
}
100107

101108
return (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import {
2+
Heading,
3+
Text,
4+
MultiStep,
5+
Button,
6+
TextArea,
7+
Avatar,
8+
} from '@ignite-ui/react'
9+
import { ArrowRight } from 'phosphor-react'
10+
import { useForm } from 'react-hook-form'
11+
import { z } from 'zod'
12+
import { zodResolver } from '@hookform/resolvers/zod'
13+
import { Container, Header } from '../styles'
14+
import { FormAnnotation, ProfileBox } from './styles'
15+
import { getSession, useSession } from 'next-auth/react'
16+
import { api } from '@/lib/axios'
17+
import { useRouter } from 'next/router'
18+
import { GetServerSideProps } from 'next'
19+
20+
const updateProfileSchema = z.object({
21+
bio: z.string(),
22+
})
23+
24+
type UpdateProfileData = z.infer<typeof updateProfileSchema>
25+
26+
export default function UpdateProfile() {
27+
const {
28+
register,
29+
handleSubmit,
30+
formState: { isSubmitting },
31+
} = useForm<UpdateProfileData>({
32+
resolver: zodResolver(updateProfileSchema),
33+
})
34+
35+
const session = useSession()
36+
const router = useRouter()
37+
38+
async function handleUpdateProfile(data: UpdateProfileData) {
39+
await api.put('/users/profile', {
40+
bio: data.bio,
41+
})
42+
await router.push(`/schedule/${session.data?.user.username}`)
43+
}
44+
45+
return (
46+
<Container>
47+
<Header>
48+
<Heading as={'strong'}>Bem-vindo ao Ignite Call!</Heading>
49+
<Text>
50+
Precisamos de algumas informações para criar seu perfil! Ah, você pode
51+
editar essas informações depois.
52+
</Text>
53+
<MultiStep size={4} currentStep={4} />
54+
</Header>
55+
56+
<ProfileBox as="form" onSubmit={handleSubmit(handleUpdateProfile)}>
57+
<label>
58+
<Text>Foto de perfil</Text>
59+
<Avatar
60+
src={session.data?.user.avatar_url}
61+
alt={session.data?.user.name}
62+
/>
63+
</label>
64+
<label>
65+
<Text size={'sm'}>Sobre você</Text>
66+
<TextArea {...register('bio')} />
67+
<FormAnnotation size={'sm'}>
68+
Fale um pouco sobre você. Isto será exibido em sua página pessoal.
69+
</FormAnnotation>
70+
</label>
71+
72+
<Button type="submit" disabled={isSubmitting}>
73+
Finalizar
74+
<ArrowRight />
75+
</Button>
76+
</ProfileBox>
77+
</Container>
78+
)
79+
}
80+
81+
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
82+
const session = await getSession({ req })
83+
84+
return {
85+
props: {
86+
session,
87+
},
88+
}
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Box, styled, Text } from '@ignite-ui/react'
2+
3+
export const ProfileBox = styled(Box, {
4+
marginTop: '$6',
5+
display: 'flex',
6+
flexDirection: 'column',
7+
gap: '$4',
8+
9+
label: {
10+
display: 'flex',
11+
flexDirection: 'column',
12+
gap: '$2',
13+
},
14+
})
15+
16+
export const FormAnnotation = styled(Text, {
17+
color: '$gray200',
18+
})

0 commit comments

Comments
 (0)