From 9c65a9c271dfda5ea17c9d909bc9e7e6d0c040ab Mon Sep 17 00:00:00 2001 From: l3wdfut4pwr Date: Fri, 3 Apr 2026 23:59:33 +0300 Subject: add profile --- src/app/globals.css | 48 ++++++++++++- src/app/profile/[username]/page.tsx | 83 +++++++++++++++++++++++ src/app/profile/page.tsx | 3 - src/components/header/ProfileOrLogin.tsx | 6 +- src/components/header/authdialog/RegisterForm.tsx | 6 +- src/components/settings/ProfilePage.tsx | 20 +----- src/lib/api/user.ts | 13 ++++ src/lib/contexts/Auth.context.tsx | 30 +++++++- 8 files changed, 178 insertions(+), 31 deletions(-) create mode 100644 src/app/profile/[username]/page.tsx delete mode 100644 src/app/profile/page.tsx create mode 100644 src/lib/api/user.ts (limited to 'src') diff --git a/src/app/globals.css b/src/app/globals.css index 5ca3a6b..ca0c3c7 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -27,7 +27,6 @@ --light-violet: #8784c9; --dark-indigo: #0d0c1c; --red: #e64c4f; - --radius: 0.625rem; --card: oklch(1 0 0); --card-foreground: oklch(0.13 0.028 261.692); @@ -106,6 +105,53 @@ --radius-4xl: calc(var(--radius) + 16px); } +@layer utilities { + .gradient-0 { + background-image: linear-gradient(89.91deg, #8784c9 0%, #464199 99.92%); + } + .gradient-1 { + background-image: linear-gradient( + 284.32deg, + #ffafbd 20.33%, + #dae2f8 79.67% + ); + } + .gradient-2 { + background-image: linear-gradient(267.9deg, #473b7b 0%, #30d2be 100%); + } + .gradient-3 { + background-image: linear-gradient(88.87deg, #c33764 0%, #1d2671 100%); + } + .gradient-4 { + background-image: linear-gradient(267.9deg, #134e5e 0%, #71b280 100%); + } + .gradient-5 { + background-image: linear-gradient(87.9deg, #423aa2 0%, #100626 100%); + } + .gradient-6 { + background-image: linear-gradient(87.9deg, #edf3f6 0%, #d9eaf4 100%); + } + .gradient-7 { + background-image: linear-gradient( + 284.32deg, + #212121 20.33%, + #454545 79.67% + ); + } + .gradient-8 { + background-image: linear-gradient(88.87deg, #610000 0%, #190a05 100%); + } + .gradient-9 { + background-image: linear-gradient(87.9deg, #ffc500 0%, #c21500 100%); + } + .gradient-10 { + background-image: linear-gradient(270deg, #6a11cb 0%, #69a1ff 100%); + } + .gradient-11 { + background-image: linear-gradient(267.9deg, #182848 0%, #4b6cb7 100%); + } +} + @layer base { * { @apply border-violet outline-ring/50; diff --git a/src/app/profile/[username]/page.tsx b/src/app/profile/[username]/page.tsx new file mode 100644 index 0000000..cad11bb --- /dev/null +++ b/src/app/profile/[username]/page.tsx @@ -0,0 +1,83 @@ +import Image from 'next/image'; +import { Button } from '@/components/ui'; +import { getUserByUsername } from '@/lib/api/user'; +import { User } from '@/lib/contexts/Auth.context'; +interface ProfilePageProps { + params: Promise<{ username: string }>; +} + +export default async function Profile({ params }: ProfilePageProps) { + const { username } = await params; + + const profileUser: User = await getUserByUsername(username); + const icons = [ + 'facebook', + 'pinterest', + 'discord', + 'artstation', + 'behance', + 'instagram', + ] as const; + + type IconKey = (typeof icons)[number]; + return ( + <> +
+
+
+
+
+

+ {profileUser.username} +

+
+
+

+ {profileUser.profile?.publications_count ?? 0}{' '} + публикаций +

+

+ {profileUser.profile?.collections_count ?? 0}{' '} + коллекций +

+

+ {profileUser.profile?.followers_count ?? 0}{' '} + подписчиков +

+

+ {profileUser.profile?.following_count ?? 0}{' '} + подписок +

+
+
+

{profileUser.description}

+
+
+ {icons + .filter( + (icon: IconKey) => + profileUser.integrations?.[icon], + ) + .map((icon: IconKey) => ( + + {icon} + + ))}{' '} +
+
+
+
+ +
+ + ); +} diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx deleted file mode 100644 index 17e3f62..0000000 --- a/src/app/profile/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Profile() { - return <>; -} diff --git a/src/components/header/ProfileOrLogin.tsx b/src/components/header/ProfileOrLogin.tsx index 416418b..68c81f6 100644 --- a/src/components/header/ProfileOrLogin.tsx +++ b/src/components/header/ProfileOrLogin.tsx @@ -21,11 +21,11 @@ export function ProfileOrLogin() { ); } - + const profileLink = `/profile/${user.username}`; return ( - + @@ -56,11 +41,10 @@ export default function ProfilePage() {

- {gradients.map((gradient, index) => ( + {Array.from({ length: 12 }).map((_, index) => (
))}
diff --git a/src/lib/api/user.ts b/src/lib/api/user.ts new file mode 100644 index 0000000..86dfce8 --- /dev/null +++ b/src/lib/api/user.ts @@ -0,0 +1,13 @@ +const API_URL = process.env.NEXT_PUBLIC_API_URL; + +export async function getUserByUsername(username: string) { + if (!username) throw new Error('Username is required'); + + const res = await fetch(`${API_URL}/api/users/${username}`, { + cache: 'no-store', + }); + + if (!res.ok) throw new Error(`User not found: ${username}`); + + return res.json(); +} diff --git a/src/lib/contexts/Auth.context.tsx b/src/lib/contexts/Auth.context.tsx index fbf2e24..4e567ba 100644 --- a/src/lib/contexts/Auth.context.tsx +++ b/src/lib/contexts/Auth.context.tsx @@ -4,12 +4,38 @@ import React, { createContext, useState, useContext, useEffect } from 'react'; export type User = { id: number; username: string; + email: string; + password?: string; avatar?: string; banner_file?: string; + description?: string; premium?: boolean; is_banned?: boolean; is_moderator?: boolean; + token_version?: number; + profile?: { + id: number; + user_id: number; + avatar_file?: string; + banner_file?: string; + description?: string; + publications_count?: number; + collections_count?: number; + subscriptions_count?: number; + followers_count?: number; + following_count?: number; + }; + integrations?: { + facebook?: string | null; + pinterest?: string | null; + discord?: string | null; + artstation?: string | null; + x?: string | null; // Twitter/X + behance?: string | null; + instagram?: string | null; + }; }; + interface AuthContextType { user: User | null; setUser: (user: User | null) => void; @@ -33,7 +59,9 @@ export const AuthContextProvider = ({ children }: React.PropsWithChildren) => { if (!res.ok) return; const userData = await res.json(); setUser(userData); - } catch {} + } catch (err) { + console.error('Error fetching user:', err); + } }; fetchUser(); -- cgit v1.3-3-g829e