Skip to content

Commit 6242f6c

Browse files
committed
working on db
1 parent 097c509 commit 6242f6c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+10079
-892
lines changed

.editorconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Top-most EditorConfig file
2+
root = true
3+
4+
# Set default charset to UTF-8
5+
[*]
6+
charset = utf-8
7+
indent_style = space
8+
indent_size = 2
9+
10+
# End of EditorConfig file

.prettier.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ module.exports = {
1717
importOrderSortSpecifiers: true,
1818
plugins: [
1919
require('prettier-plugin-tailwindcss'),
20-
require('@ianvs/prettier-plugin-sort-imports')
21-
]
20+
require('@ianvs/prettier-plugin-sort-imports'),
21+
],
2222
};

app/auth/[...nextAuth]/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import auth from 'auth';
2+
3+
export const GET = () => {
4+
return Response.json({
5+
message: 'Hello, World!',
6+
});
7+
};

app/auth/callback/route.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { encryptData, getSession } from 'lib/session';
2+
import { redirect } from 'next/navigation';
3+
import { createUser, findOrCreateUser, findUserByEmail } from 'services/user';
4+
5+
export async function GET(request: Request) {
6+
const session = await getSession();
7+
8+
const query = new URL(request.url).searchParams;
9+
const code = query.get('code');
10+
11+
const accessToken = await fetch(
12+
'https://github.com/login/oauth/access_token',
13+
{
14+
method: 'POST',
15+
headers: {
16+
'Content-Type': 'application/json',
17+
Accept: 'application/json',
18+
},
19+
body: JSON.stringify({
20+
client_id: process.env.GITHUB_ID,
21+
client_secret: process.env.GITHUB_SECRET,
22+
code,
23+
}),
24+
}
25+
);
26+
27+
const result = await accessToken.json();
28+
29+
if (result.error) {
30+
return new Response(result.error, { status: 400 });
31+
}
32+
33+
const resultUser = await fetch('https://api.github.com/user', {
34+
headers: {
35+
Authorization: `Bearer ${result.access_token}`,
36+
},
37+
});
38+
const userInfo = await resultUser.json();
39+
40+
const resultEmails = await fetch('https://api.github.com/user/emails', {
41+
headers: {
42+
Authorization: `Bearer ${result.access_token}`,
43+
},
44+
});
45+
const emails = await resultEmails.json();
46+
47+
const [user] = await findOrCreateUser(userInfo.id, {
48+
username: userInfo.login,
49+
email: emails.find((email: any) => email.primary)?.email,
50+
name: userInfo.name || userInfo.login,
51+
bio: userInfo.bio,
52+
avatar: userInfo.avatar_url,
53+
githubId: userInfo.id,
54+
hireable: userInfo.hireable,
55+
refreshToken: await encryptData({
56+
token: result.refresh_token,
57+
expires: result.refresh_token_expires_in,
58+
}),
59+
});
60+
61+
session.token = result.access_token;
62+
session.expires = result.expires_in;
63+
session.userId = user.id;
64+
65+
await session.save();
66+
67+
redirect('/');
68+
}

app/auth/login/page.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default function Page() {
2+
return (
3+
<div>
4+
<a
5+
href={`https://github.com/login/oauth/authorize?client_id=${process.env.GITHUB_ID}`}>
6+
Login with github
7+
</a>
8+
</div>
9+
);
10+
}

app/challenge/[slug]/page.tsx

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
import clsx from 'clsx';
2+
import FigmaPreview from 'components/FigmaPreview';
3+
import Meta from 'components/Meta';
4+
import challenges from 'data/challenges';
25
import { Interfaces } from 'doodle-icons';
36
import { ExternalLink } from 'lucide-react';
47
import Image from 'next/image';
58
import { notFound } from 'next/navigation';
6-
7-
import challenges from 'data/challenges';
8-
9-
import FigmaPreview from 'components/FigmaPreview';
10-
import Meta from 'components/Meta';
9+
import { getChallengeBySlug } from 'services/challenge-service';
1110

1211
type Params = {
1312
params: {
1413
slug: string;
1514
};
1615
};
1716

18-
export async function generateStaticParams() {
19-
return challenges.map(challenge => ({
20-
slug: challenge.slug
21-
}));
22-
}
23-
24-
async function getChallenge(slug: string) {
25-
const challenge = challenges.find(c => c.slug === slug);
26-
27-
return challenge;
28-
}
29-
3017
async function Page({ params: { slug } }: Params) {
31-
const challenge = await getChallenge(slug);
18+
const [challenge] = await getChallengeBySlug({ slug });
3219

3320
if (!challenge) {
3421
notFound();
@@ -37,9 +24,8 @@ async function Page({ params: { slug } }: Params) {
3724
return (
3825
<div
3926
style={{
40-
'--accent': challenge.accent
41-
}}
42-
>
27+
'--accent': challenge.accent,
28+
}}>
4329
<FigmaPreview src={challenge.figma} />
4430

4531
<div className="flex flex-wrap gap-10 lg:flex-nowrap">
@@ -49,8 +35,7 @@ async function Page({ params: { slug } }: Params) {
4935
'relative p-10 lg:p-20',
5036
'border-4 border-black bg-[var(--accent)]',
5137
'shadow-solid'
52-
)}
53-
>
38+
)}>
5439
<h1 className="font-display text-2xl lg:text-4xl">
5540
{challenge.name}
5641
</h1>
@@ -90,14 +75,12 @@ async function Page({ params: { slug } }: Params) {
9075
'relative px-10 py-10',
9176
'border-4 border-black bg-brand',
9277
'shadow-solid'
93-
)}
94-
>
78+
)}>
9579
<a
9680
href={challenge.figma}
9781
target="_blank"
9882
rel="noopener noreferrer"
99-
className="flex items-center justify-center gap-4 border-2 border-black bg-[#2AE876] py-4 text-2xl"
100-
>
83+
className="flex items-center justify-center gap-4 border-2 border-black bg-[#2AE876] py-4 text-2xl">
10184
<Interfaces.Download
10285
width={24}
10386
height={24}
@@ -110,8 +93,7 @@ async function Page({ params: { slug } }: Params) {
11093
<a
11194
href="https://creativecommons.org/licenses/by/4.0/"
11295
target="_blank"
113-
rel="noreferrer"
114-
>
96+
rel="noreferrer">
11597
Read The License
11698
</a>
11799
</p>
@@ -122,8 +104,7 @@ async function Page({ params: { slug } }: Params) {
122104
'border-4 border-black bg-[#00FABE]',
123105
'space-y-8',
124106
'shadow-solid'
125-
)}
126-
>
107+
)}>
127108
<Meta
128109
icon={Interfaces.Dashboard2}
129110
name="Difficulty"
@@ -139,13 +120,12 @@ async function Page({ params: { slug } }: Params) {
139120
className={clsx(
140121
'px-10 py-10 border-4 border-black',
141122
'bg-[#FF508F] shadow-solid'
142-
)}
143-
>
123+
)}>
144124
<h2 className="text-2xl font-semibold">
145-
UI {challenge.designer.length > 1 ? 'designers' : 'designer'}
125+
UI {challenge.designers.length > 1 ? 'designers' : 'designer'}
146126
</h2>
147127
<div className="mt-4">
148-
{challenge.designer.map(designer => (
128+
{challenge.designers.map((designer) => (
149129
<div key={designer.name} className="flex items-center mt-4">
150130
<Image
151131
src={designer.avatar}
@@ -159,11 +139,10 @@ async function Page({ params: { slug } }: Params) {
159139
{designer.name}
160140
</h3>
161141
<a
162-
href={designer.url}
142+
href={designer.links[0].link}
163143
target="_blank"
164144
rel="noopener noreferrer"
165-
className="inline-flex items-center hover:underline"
166-
>
145+
className="inline-flex items-center hover:underline">
167146
Visit Profile <ExternalLink width={18} className="ml-2" />
168147
</a>
169148
</div>

app/challenges/page.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import CategoriesSelector from 'components/CategoriesSelector';
2+
import Challenges from 'components/Challenges';
3+
import DifficultiesSelector from 'components/DifficultiesSelector';
4+
import LoadMore from 'components/LoadMore';
5+
import {
6+
type GetChallengesParams,
7+
getChallenges,
8+
} from 'services/challenge-service';
9+
10+
async function loadMore(offset, params) {
11+
'use server';
12+
13+
const { challenges } = await getChallenges({
14+
...params,
15+
offset,
16+
});
17+
18+
return <Challenges challenges={challenges} />;
19+
}
20+
21+
export default async function Page({
22+
searchParams,
23+
}: {
24+
searchParams: { [key: string]: string | string[] | undefined };
25+
}) {
26+
const dataParams: GetChallengesParams = {
27+
where: {
28+
difficultyId: Number(searchParams.difficulty) || undefined,
29+
categoryId: Number(searchParams.category) || undefined,
30+
},
31+
};
32+
33+
const { challenges, limit, total } = await getChallenges(dataParams);
34+
35+
return (
36+
<section className="flex flex-col">
37+
<div className="flex flex-wrap items-center gap-3 lg:gap-5 mb-10">
38+
<div>
39+
<DifficultiesSelector />
40+
</div>
41+
<div>
42+
<CategoriesSelector />
43+
</div>
44+
</div>
45+
46+
<LoadMore
47+
loadMoreAction={loadMore}
48+
loadMoreParams={dataParams}
49+
limit={limit}
50+
total={total}
51+
className="space-y-10">
52+
<Challenges challenges={challenges} />
53+
</LoadMore>
54+
</section>
55+
);
56+
}

app/layout.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
import 'tailwindcss/tailwind.css';
2-
3-
import { Fredoka_One, Patrick_Hand } from '@next/font/google';
42
import clsx from 'clsx';
5-
import { PropsWithChildren } from 'react';
6-
73
import { AnalyticsWrapper } from 'components/Analytics';
84
import Header from 'components/Header';
95
import ScrollToTop from 'components/ScrollToTop';
6+
import { Fredoka, Patrick_Hand } from 'next/font/google';
7+
import { PropsWithChildren } from 'react';
108

11-
const fontDisplay = Fredoka_One({
9+
const fontDisplay = Fredoka({
1210
variable: '--font-display',
1311
weight: '400',
14-
subsets: ['latin']
12+
subsets: ['latin'],
1513
});
1614

1715
const fontSans = Patrick_Hand({
1816
variable: '--font-sans',
1917
weight: '400',
20-
subsets: ['latin']
18+
subsets: ['latin'],
2119
});
2220

2321
export default function RootLayout({ children }: PropsWithChildren) {
@@ -26,9 +24,8 @@ export default function RootLayout({ children }: PropsWithChildren) {
2624
lang="en"
2725
className={clsx(fontDisplay.variable, fontSans.variable)}
2826
style={{
29-
'--primary-blue': '#1F4290'
30-
}}
31-
>
27+
'--primary-blue': '#1F4290',
28+
}}>
3229
<head />
3330
<body className="bg-[var(--primary-blue)]">
3431
<main className="mx-auto px-6 pt-10 pb-40 lg:py-20 xl:px-0 xl:w-[1140px]">
@@ -40,8 +37,7 @@ export default function RootLayout({ children }: PropsWithChildren) {
4037
href="https://twitter.com/mhdnauvalazhar"
4138
target="_blank"
4239
className="border-brand border-b-2"
43-
rel="noreferrer"
44-
>
40+
rel="noreferrer">
4541
Nauval
4642
</a>
4743
<p>Powered by Vercel</p>

app/manual/page.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import clsx from 'clsx';
2+
import { getSession } from 'lib/session';
23

3-
export default function Page() {
4+
export default async function Page() {
5+
const session = await getSession();
6+
console.log(session);
47
return (
58
<div
69
className={clsx(
710
'relative p-10 lg:p-20',
811
'border-4 border-black bg-brand',
912
'shadow-solid'
10-
)}
11-
>
13+
)}>
1214
<h1 className="font-display text-2xl lg:text-4xl">Manual</h1>
1315
<div className="mt-4 space-y-6 text-xl lg:text-2xl">
1416
<h2 className="font-display text-xl lg:text-2xl">Motivation</h2>

0 commit comments

Comments
 (0)