diff options
| author | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2026-04-03 23:59:33 +0300 |
|---|---|---|
| committer | l3wdfut4pwr <l3wdfut4pwr@gmail.com> | 2026-04-03 23:59:33 +0300 |
| commit | 9c65a9c271dfda5ea17c9d909bc9e7e6d0c040ab (patch) | |
| tree | 9df45f5df63fb509e1b7cdac81659c4713287d70 /src | |
| parent | 1d20080db8a26e4b7dd4071daac1166142592afa (diff) | |
add profile
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/globals.css | 48 | ||||
| -rw-r--r-- | src/app/profile/[username]/page.tsx | 83 | ||||
| -rw-r--r-- | src/app/profile/page.tsx | 3 | ||||
| -rw-r--r-- | src/components/header/ProfileOrLogin.tsx | 6 | ||||
| -rw-r--r-- | src/components/header/authdialog/RegisterForm.tsx | 6 | ||||
| -rw-r--r-- | src/components/settings/ProfilePage.tsx | 20 | ||||
| -rw-r--r-- | src/lib/api/user.ts | 13 | ||||
| -rw-r--r-- | src/lib/contexts/Auth.context.tsx | 30 |
8 files changed, 178 insertions, 31 deletions
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 ( + <> + <div className="flex gap-[20px] flex-col"> + <div className="flex flex-col flex-start padding-0 gap-[20px] h-[551px] w-full"> + <div className="gradient-0 flex flex-end padding-[20px] gap-[10px] h-[350px] w-full rounded-[20px]"></div> + <div className="flex flex-col flex-start gap-[10px] w-full h-[181px]"> + <div className="flex flex-col gap-1.25"> + <p className="font-medium text-[24px]"> + {profileUser.username} + </p> + </div> + <div className="flex flex-row items-center gap-1.25 h-[19px]"> + <p> + {profileUser.profile?.publications_count ?? 0}{' '} + публикаций + </p> + <p> + {profileUser.profile?.collections_count ?? 0}{' '} + коллекций + </p> + <p> + {profileUser.profile?.followers_count ?? 0}{' '} + подписчиков + </p> + <p> + {profileUser.profile?.following_count ?? 0}{' '} + подписок + </p> + </div> + <div className="flex max-w-[800px] font-regular text-[12px] gap-1.25"> + <p>{profileUser.description}</p> + </div> + <div className="flex flex-row flex-end gap-1.25"> + {icons + .filter( + (icon: IconKey) => + profileUser.integrations?.[icon], + ) + .map((icon: IconKey) => ( + <a + key={icon} + href={profileUser.integrations![icon]!} + target="_blank" + rel="noopener noreferrer" + > + <img + src={`/profile/${icon}.svg`} + alt={icon} + className="w-[30px] h-[40px]" + /> + </a> + ))}{' '} + </div> + </div> + </div> + <div className="flex flex-row space-between flex-start gap-1.25 w-full h-[42px]"></div> + <Button>Управление аккаунтом</Button> + </div> + </> + ); +} 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() { </Dialog> ); } - + const profileLink = `/profile/${user.username}`; return ( - <Link href={'/profile'}> + <Link href={profileLink}> <Image - src={user?.avatar ?? 'icons/avatar.svg'} + src={user?.avatar ?? '/icons/avatar.svg'} alt="" width={60} height={60} diff --git a/src/components/header/authdialog/RegisterForm.tsx b/src/components/header/authdialog/RegisterForm.tsx index c8ddb55..0370671 100644 --- a/src/components/header/authdialog/RegisterForm.tsx +++ b/src/components/header/authdialog/RegisterForm.tsx @@ -41,12 +41,8 @@ export default function RegisterForm() { if (error) { setErrors(error); } else if (data) { - setUser({ - id: data.id, - username: data.username, - }); + setUser(data); } - setLoading(false); }; diff --git a/src/components/settings/ProfilePage.tsx b/src/components/settings/ProfilePage.tsx index 60ff41f..9d5b81b 100644 --- a/src/components/settings/ProfilePage.tsx +++ b/src/components/settings/ProfilePage.tsx @@ -3,21 +3,6 @@ import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui'; import { Separator } from '@/components/ui'; -const gradients = [ - 'linear-gradient(89.91deg, #8784C9 0%, #464199 99.92%)', - 'linear-gradient(284.32deg, #FFAFBD 20.33%, #DAE2F8 79.67%)', - 'linear-gradient(267.9deg, #473B7B 0%, #30D2BE 100%)', - 'linear-gradient(88.87deg, #C33764 0%, #1D2671 100%)', - 'linear-gradient(267.9deg, #134E5E 0%, #71B280 100%)', - 'linear-gradient(87.9deg, #423AA2 0%, #100626 100%)', - 'linear-gradient(87.9deg, #EDF3F6 0%, #D9EAF4 100%)', - 'linear-gradient(284.32deg, #212121 20.33%, #454545 79.67%)', - 'linear-gradient(88.87deg, #610000 0%, #190A05 100%)', - 'linear-gradient(87.9deg, #FFC500 0%, #C21500 100%)', - 'linear-gradient(270deg, #6A11CB 0%, #69A1FF 100%)', - 'linear-gradient(267.9deg, #182848 0%, #4B6CB7 100%)', -]; - export default function ProfilePage() { return ( <div className="flex flex-col flex-start gap-[20px] w-[900px] h-[804px]"> @@ -56,11 +41,10 @@ export default function ProfilePage() { </p> <div className="flex flex-row flex-wrap items-center content-start gap-[5px] w-[265px] h-[85px]"> - {gradients.map((gradient, index) => ( + {Array.from({ length: 12 }).map((_, index) => ( <div key={index} - style={{ background: gradient }} - className="w-[40px] h-[40px] rounded-full cursor-pointer" + className={`w-[40px] h-[40px] rounded-full cursor-pointer gradient-${index}`} /> ))} </div> 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(); |
