Skip to content

Commit 35066cc

Browse files
committed
🍓 Auth fixes
1 parent 238ae44 commit 35066cc

File tree

7 files changed

+82
-26
lines changed

7 files changed

+82
-26
lines changed

app/anime/[id]/layout.tsx

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
import NavBar from "@/components/main/NavBar";
1+
import AuthBadgs, { AUTH_BADGE_FRAGMENT } from "@/components/main/profile/AuthBadgs";
2+
import { AuthBadgeFragment, SettingsQuery } from "@/lib/types/anilist";
3+
import { Anilist } from "@/utils/anilist";
4+
import gql from "graphql-tag";
25

3-
export default function Layout({
6+
export default async function Layout({
47
children,
58
}: {
69
children: React.ReactNode;
7-
}) {
8-
return (
9-
<main className="">
10-
<NavBar/>
11-
{children}
12-
</main>
10+
}) {
11+
12+
const queryRes = await Anilist<SettingsQuery>(
13+
gql`query Settings{
14+
Viewer {
15+
...AuthBadge
16+
}
17+
}
18+
${AUTH_BADGE_FRAGMENT}`
1319
);
20+
21+
return <main className="container mx-auto md:px-4 pt-8">
22+
<AuthBadgs generate={false} {...queryRes.Viewer as AuthBadgeFragment} />
23+
{children}
24+
</main>
25+
1426
}

app/api/auth/callback/route.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { fetchAniList } from '@/lib/auth';
55
export async function GET(request: NextRequest) {
66
const searchParams = request.nextUrl.searchParams;
77
const code = searchParams.get('code');
8+
const age = 60 * 60 * 24 * 7 * 8;
89

910
if (!code) {
1011
return new Response('No code provided', { status: 400 });
@@ -32,13 +33,12 @@ export async function GET(request: NextRequest) {
3233
throw new Error(data.error || 'Failed to get token');
3334
}
3435

35-
// Set the cookie
3636
const cookieStore = await cookies();
3737
cookieStore.set('anilist_token', data.access_token, {
38-
httpOnly: true,
38+
httpOnly: false,
3939
secure: process.env.NODE_ENV === 'production',
4040
sameSite: 'lax',
41-
maxAge: 60 * 60 * 24 * 7 * 1, // 1 week
41+
maxAge: age, // 8 week
4242
});
4343

4444
const userData = await fetchAniList<any>(
@@ -55,11 +55,17 @@ export async function GET(request: NextRequest) {
5555
data.access_token
5656
);
5757
const viewer = userData.data.Viewer;
58-
cookieStore.set('user', JSON.stringify({name:viewer.name, id:viewer.id, avatar:viewer.avatar.large}), {
59-
httpOnly: true,
58+
cookieStore.set('user', JSON.stringify({ name: viewer.name, id: viewer.id, avatar: viewer.avatar.large }), {
59+
httpOnly: false,
6060
secure: process.env.NODE_ENV === 'production',
6161
sameSite: 'lax',
62-
maxAge: 60 * 60 * 24 * 7 * 4, // 4 week
62+
maxAge: age, // 4 week
63+
});
64+
cookieStore.set('anilist_id', viewer.id, {
65+
httpOnly: false,
66+
secure: process.env.NODE_ENV === 'production',
67+
sameSite: 'lax',
68+
maxAge: age, // 4 week
6369
});
6470

6571
return new Response(null, {

app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default async function RootLayout({
77
}: {
88
children: React.ReactNode;
99
}) {
10-
const theme = (await cookies()).get(currentTheme)?.value
10+
const theme = (await cookies()).get(currentTheme)?.value;
1111
return (
1212
<html data-theme={theme} lang="en">
1313
<body>

components/main/profile/AuthBadgs.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { AuthBadgeFragment } from "@/lib/types/anilist";
22
import gql from "graphql-tag";
33
import GenerateCalendar from "./GenerateCalendar";
44
import ProfileSettingsRouter from "./ProfileSettingsRouter";
5+
import HomeIcon from "~icons/gravity-ui/house";
6+
import SettingsIcon from "~icons/gravity-ui/gear";
7+
import Link from "next/link";
58

69
export const AUTH_BADGE_FRAGMENT = gql`
710
fragment AuthBadge on User {
@@ -21,7 +24,8 @@ export const AUTH_BADGE_FRAGMENT = gql`
2124

2225
export default ({ generate = true, ...viewer }: AuthBadgeFragment & { generate?: boolean }) => {
2326
return <div className="flex justify-between items-center md:flex-row flex-col md:mb-0 mb-6">
24-
<div className="flex items-center space-x-4 mb-8 group">
27+
<div className="flex items-center gap-2 mb-8 group">
28+
<Navigation />
2529
<div className="avatar">
2630
<ProfileSettingsRouter />
2731
<div className="w-24 rounded-full">
@@ -43,4 +47,20 @@ export default ({ generate = true, ...viewer }: AuthBadgeFragment & { generate?:
4347
</div>
4448
{generate ? <GenerateCalendar /> : null}
4549
</div>
46-
}
50+
}
51+
52+
export const Navigation = () => <div className="join join-vertical">
53+
<Link href={"/"} className="join-item btn btn-sm btn-square">
54+
<HomeIcon />
55+
</Link>
56+
<Link href={"/settings"} className="join-item btn btn-sm btn-square">
57+
<SettingsIcon />
58+
</Link>
59+
<Link href={"https://github.com/adenlall/anical"} className="join-item btn btn-sm btn-square">
60+
<GitHubIcon className="fill-base-content w-5 h-5" />
61+
</Link>
62+
</div>
63+
64+
const GitHubIcon = ({ className }: { className?: string }) => <svg className={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
65+
<path d="M16.24 22a1 1 0 0 1-1-1v-2.6a2.15 2.15 0 0 0-.54-1.66a1 1 0 0 1 .61-1.67C17.75 14.78 20 14 20 9.77a4 4 0 0 0-.67-2.22a2.75 2.75 0 0 1-.41-2.06a3.7 3.7 0 0 0 0-1.41a7.7 7.7 0 0 0-2.09 1.09a1 1 0 0 1-.84.15a10.15 10.15 0 0 0-5.52 0a1 1 0 0 1-.84-.15a7.4 7.4 0 0 0-2.11-1.09a3.5 3.5 0 0 0 0 1.41a2.84 2.84 0 0 1-.43 2.08a4.07 4.07 0 0 0-.67 2.23c0 3.89 1.88 4.93 4.7 5.29a1 1 0 0 1 .82.66a1 1 0 0 1-.21 1a2.06 2.06 0 0 0-.55 1.56V21a1 1 0 0 1-2 0v-.57a6 6 0 0 1-5.27-2.09a3.9 3.9 0 0 0-1.16-.88a1 1 0 1 1 .5-1.94a4.9 4.9 0 0 1 2 1.36c1 1 2 1.88 3.9 1.52a3.9 3.9 0 0 1 .23-1.58c-2.06-.52-5-2-5-7a6 6 0 0 1 1-3.33a.85.85 0 0 0 .13-.62a5.7 5.7 0 0 1 .33-3.21a1 1 0 0 1 .63-.57c.34-.1 1.56-.3 3.87 1.2a12.16 12.16 0 0 1 5.69 0c2.31-1.5 3.53-1.31 3.86-1.2a1 1 0 0 1 .63.57a5.7 5.7 0 0 1 .33 3.22a.75.75 0 0 0 .11.57a6 6 0 0 1 1 3.34c0 5.07-2.92 6.54-5 7a4.3 4.3 0 0 1 .22 1.67V21a1 1 0 0 1-.94 1"></path>
66+
</svg>

lib/types/anilist.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4670,12 +4670,17 @@ export type YearStats = {
46704670
year?: Maybe<Scalars['Int']['output']>;
46714671
};
46724672

4673+
export type SettingsQueryVariables = Exact<{ [key: string]: never; }>;
4674+
4675+
4676+
export type SettingsQuery = { __typename?: 'Query', Viewer?: { __typename?: 'User', id: number, name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null, statistics?: { __typename?: 'UserStatisticTypes', anime?: { __typename?: 'UserStatistics', count: number, episodesWatched: number } | null } | null } | null };
4677+
46734678
export type AnimeHeaderQueryVariables = Exact<{
46744679
id?: InputMaybe<Scalars['Int']['input']>;
46754680
}>;
46764681

46774682

4678-
export type AnimeHeaderQuery = { __typename?: 'Query', Media?: { __typename?: 'Media', description?: string | null, genres?: Array<string | null> | null, format?: MediaFormat | null, meanScore?: number | null, favourites?: number | null, coverImage?: { __typename?: 'MediaCoverImage', large?: string | null } | null, title?: { __typename?: 'MediaTitle', romaji?: string | null, english?: string | null } | null, reviews?: { __typename?: 'ReviewConnection', edges?: Array<{ __typename?: 'ReviewEdge', node?: { __typename?: 'Review', summary?: string | null, rating?: number | null, score?: number | null, user?: { __typename?: 'User', name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null } | null } | null } | null> | null } | null, studios?: { __typename?: 'StudioConnection', edges?: Array<{ __typename?: 'StudioEdge', node?: { __typename?: 'Studio', name: string, favourites?: number | null } | null } | null> | null } | null, staff?: { __typename?: 'StaffConnection', edges?: Array<{ __typename?: 'StaffEdge', role?: string | null, node?: { __typename?: 'Staff', primaryOccupations?: Array<string | null> | null, name?: { __typename?: 'StaffName', userPreferred?: string | null } | null, image?: { __typename?: 'StaffImage', medium?: string | null } | null } | null } | null> | null } | null } | null };
4683+
export type AnimeHeaderQuery = { __typename?: 'Query', Media?: { __typename?: 'Media', description?: string | null, genres?: Array<string | null> | null, format?: MediaFormat | null, meanScore?: number | null, favourites?: number | null, coverImage?: { __typename?: 'MediaCoverImage', large?: string | null } | null, title?: { __typename?: 'MediaTitle', romaji?: string | null, english?: string | null, userPreferred?: string | null } | null, characters?: { __typename?: 'CharacterConnection', edges?: Array<{ __typename?: 'CharacterEdge', node?: { __typename?: 'Character', favourites?: number | null, name?: { __typename?: 'CharacterName', first?: string | null } | null, image?: { __typename?: 'CharacterImage', medium?: string | null } | null } | null, voiceActors?: Array<{ __typename?: 'Staff', name?: { __typename?: 'StaffName', native?: string | null } | null, image?: { __typename?: 'StaffImage', medium?: string | null } | null } | null> | null } | null> | null } | null, reviews?: { __typename?: 'ReviewConnection', edges?: Array<{ __typename?: 'ReviewEdge', node?: { __typename?: 'Review', summary?: string | null, rating?: number | null, score?: number | null, user?: { __typename?: 'User', name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null } | null } | null } | null> | null } | null, studios?: { __typename?: 'StudioConnection', edges?: Array<{ __typename?: 'StudioEdge', node?: { __typename?: 'Studio', name: string, favourites?: number | null } | null } | null> | null } | null, staff?: { __typename?: 'StaffConnection', edges?: Array<{ __typename?: 'StaffEdge', role?: string | null, node?: { __typename?: 'Staff', primaryOccupations?: Array<string | null> | null, name?: { __typename?: 'StaffName', userPreferred?: string | null } | null, image?: { __typename?: 'StaffImage', medium?: string | null } | null } | null } | null> | null } | null } | null };
46794684

46804685
export type ProfileQueryVariables = Exact<{
46814686
status?: InputMaybe<MediaListStatus>;
@@ -4686,13 +4691,6 @@ export type ProfileQueryVariables = Exact<{
46864691

46874692
export type ProfileQuery = { __typename?: 'Query', Viewer?: { __typename?: 'User', id: number, name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null, statistics?: { __typename?: 'UserStatisticTypes', anime?: { __typename?: 'UserStatistics', count: number, episodesWatched: number } | null } | null } | null, Page?: { __typename?: 'Page', mediaList?: Array<{ __typename?: 'MediaList', media?: { __typename?: 'Media', id: number, description?: string | null, status?: MediaStatus | null, format?: MediaFormat | null, coverImage?: { __typename?: 'MediaCoverImage', large?: string | null } | null, title?: { __typename?: 'MediaTitle', romaji?: string | null, english?: string | null, userPreferred?: string | null } | null } | null } | null> | null } | null };
46884693

4689-
export type SettingsQueryVariables = Exact<{
4690-
userId?: InputMaybe<Scalars['Int']['input']>;
4691-
}>;
4692-
4693-
4694-
export type SettingsQuery = { __typename?: 'Query', Viewer?: { __typename?: 'User', id: number, name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null, statistics?: { __typename?: 'UserStatisticTypes', anime?: { __typename?: 'UserStatistics', count: number, episodesWatched: number } | null } | null } | null };
4695-
46964694
export type AnimeCardFragment = { __typename?: 'Media', id: number, description?: string | null, status?: MediaStatus | null, format?: MediaFormat | null, coverImage?: { __typename?: 'MediaCoverImage', large?: string | null } | null, title?: { __typename?: 'MediaTitle', romaji?: string | null, english?: string | null, userPreferred?: string | null } | null };
46974695

46984696
export type AnimeReviewsFragment = { __typename?: 'Media', reviews?: { __typename?: 'ReviewConnection', edges?: Array<{ __typename?: 'ReviewEdge', node?: { __typename?: 'Review', summary?: string | null, rating?: number | null, score?: number | null, user?: { __typename?: 'User', name: string, avatar?: { __typename?: 'UserAvatar', medium?: string | null } | null } | null } | null } | null> | null } | null };

middleware.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
import { cookies } from 'next/headers';
12
import { NextResponse } from 'next/server';
23

3-
export function middleware(request: Request) {
4+
export async function middleware(request: Request) {
45

56
const requestHeaders = new Headers(request.headers);
67
requestHeaders.set('x-url', request.url);
8+
9+
const token = (await cookies()).get("anilist_token")?.value;
10+
if (!token && (request.url.includes("profile") || request.url.includes("settings"))) {
11+
return NextResponse.redirect(new URL('/', request.url));
12+
}
13+
714
return NextResponse.next({
815
request: {
916
headers: requestHeaders,

utils/helpers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
export function formated(num: number | undefined | null): string {
3+
if (!num) {
4+
return '';
5+
}
6+
if (num < 1000) {
7+
return num.toString();
8+
} else if (num < 1000000) {
9+
return (num / 1000).toFixed(1).replace(/\.0$/, '') + ' ' + 'K';
10+
} else {
11+
return (num / 1000000).toFixed(1).replace(/\.0$/, '') + ' ' + 'M';
12+
}
13+
}

0 commit comments

Comments
 (0)