✨ Other user profile page
This commit is contained in:
parent
6a4449d93c
commit
c42e15cff0
@ -1,8 +1,11 @@
|
||||
import type { NextConfig } from "next";
|
||||
import type { NextConfig } from 'next'
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
reactStrictMode: true,
|
||||
};
|
||||
images: {
|
||||
domains: ['raw.sn.solsynth.dev', 'api.sn.solsynth.dev'],
|
||||
},
|
||||
}
|
||||
|
||||
export default nextConfig;
|
||||
export default nextConfig
|
||||
|
@ -13,6 +13,7 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.3.0",
|
||||
"@mui/material": "^6.3.0",
|
||||
"@mui/x-charts": "^7.23.2",
|
||||
"axios": "^1.7.9",
|
||||
"axios-case-converter": "^1.1.1",
|
||||
"cookies-next": "^5.0.2",
|
||||
|
114
src/pages/users/[name].tsx
Normal file
114
src/pages/users/[name].tsx
Normal file
@ -0,0 +1,114 @@
|
||||
import { SnCheckInRecord } from '@/services/checkIn'
|
||||
import { getAttachmentUrl, sni } from '@/services/network'
|
||||
import { SnAccount } from '@/services/user'
|
||||
import { Avatar, Box, Card, CardContent, Container, Grid2 as Grid, Typography } from '@mui/material'
|
||||
import { LineChart } from '@mui/x-charts'
|
||||
import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
|
||||
import Image from 'next/image'
|
||||
|
||||
export const getServerSideProps = (async (context) => {
|
||||
const name = context.params!.name as string
|
||||
try {
|
||||
const { data: user } = await sni.get<SnAccount>('/cgi/id/users/' + name)
|
||||
const { data: checkIn } = await sni.get<{ data: SnCheckInRecord[] }>('/cgi/id/users/' + name + '/check-in', {
|
||||
params: { take: 14 },
|
||||
})
|
||||
return { props: { user, checkIn: checkIn.data } }
|
||||
} catch (err) {
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
}) satisfies GetServerSideProps<{ user: SnAccount; checkIn: SnCheckInRecord[] }>
|
||||
|
||||
export default function UserProfile({ user, checkIn }: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
return (
|
||||
<>
|
||||
{user.banner && (
|
||||
<Box sx={{ aspectRatio: 16 / 5, position: 'relative' }}>
|
||||
<Image src={getAttachmentUrl(user.banner)} alt="account banner" style={{ objectFit: 'cover' }} fill />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Container sx={{ mt: 4, px: 2 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{user && <Avatar src={getAttachmentUrl(user.avatar)} />}
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography fontWeight="bold">{user.nick}</Typography>
|
||||
<Typography fontFamily="monospace" fontSize={13} lineHeight={1.2}>
|
||||
@{user.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={2} sx={{ mt: 3 }}>
|
||||
<Grid size={8}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Fortune History
|
||||
</Typography>
|
||||
<LineChart
|
||||
yAxis={[
|
||||
{
|
||||
data: [1, 2, 3, 4, 5],
|
||||
tickMinStep: 1,
|
||||
tickMaxStep: 1,
|
||||
valueFormatter(value, _) {
|
||||
const resultTierList = ['大凶', '凶', '中平', '吉', '大吉']
|
||||
return resultTierList[value]
|
||||
},
|
||||
},
|
||||
]}
|
||||
xAxis={[
|
||||
{
|
||||
scaleType: 'time',
|
||||
data: checkIn.map((c) => {
|
||||
const og = new Date(c.createdAt)
|
||||
og.setHours(0, 0, 0, 0)
|
||||
return og
|
||||
}),
|
||||
valueFormatter(value, _) {
|
||||
return new Date(value).toLocaleDateString('en-US', {
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
},
|
||||
},
|
||||
]}
|
||||
series={[
|
||||
{
|
||||
data: checkIn.map((c) => c.resultTier),
|
||||
valueFormatter(value, _) {
|
||||
const resultTierList = ['大凶', '凶', '中平', '吉', '大吉']
|
||||
return resultTierList[value ?? 0]
|
||||
},
|
||||
},
|
||||
]}
|
||||
height={300}
|
||||
margin={{ top: 16, bottom: 24 }}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid size={4}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Information
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2">
|
||||
Born on {new Date(user.profile!.birthday!).toLocaleDateString()}
|
||||
</Typography>
|
||||
<Typography variant="body2">Joined at {new Date(user.createdAt).toLocaleDateString()}</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,12 +1,40 @@
|
||||
import { checkAuthenticatedClient, redirectToLogin } from '@/services/auth'
|
||||
import { Container } from '@mui/material'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useUserStore } from '@/services/user'
|
||||
import { Avatar, Box, Container, Typography } from '@mui/material'
|
||||
import { getAttachmentUrl } from '@/services/network'
|
||||
import { useEffect } from 'react'
|
||||
import Image from 'next/image'
|
||||
|
||||
export default function UserItself() {
|
||||
useEffect(() => {
|
||||
if (!checkAuthenticatedClient()) redirectToLogin()
|
||||
}, [])
|
||||
|
||||
return <Container></Container>
|
||||
const userStore = useUserStore()
|
||||
|
||||
return (
|
||||
<>
|
||||
{userStore.account && (
|
||||
<Box sx={{ aspectRatio: 16 / 5, position: 'relative' }}>
|
||||
<Image src={getAttachmentUrl(userStore.account!.banner)} alt="account banner" objectFit="cover" fill />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Container sx={{ mt: 5 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
{userStore.account && <Avatar src={getAttachmentUrl(userStore.account!.avatar)} />}
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography fontWeight="bold">{userStore.account?.nick}</Typography>
|
||||
<Typography fontFamily="monospace" fontSize={13}>
|
||||
@{userStore.account?.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ mt: 5 }}></Box>
|
||||
</Container>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
10
src/services/checkIn.ts
Normal file
10
src/services/checkIn.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface SnCheckInRecord {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
deletedAt?: Date | null
|
||||
resultTier: number
|
||||
resultExperience: number
|
||||
resultModifiers: number[]
|
||||
accountId: number
|
||||
}
|
@ -2,7 +2,7 @@ import { create } from 'zustand'
|
||||
import { sni } from './network'
|
||||
import { hasCookie } from 'cookies-next/client'
|
||||
|
||||
interface SnAccount {
|
||||
export interface SnAccount {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
@ -24,7 +24,7 @@ interface SnAccount {
|
||||
automatedId?: number | null
|
||||
}
|
||||
|
||||
interface SnAccountContact {
|
||||
export interface SnAccountContact {
|
||||
accountId: number
|
||||
content: string
|
||||
createdAt: Date
|
||||
@ -37,7 +37,7 @@ interface SnAccountContact {
|
||||
verifiedAt?: Date | null
|
||||
}
|
||||
|
||||
interface SnAccountProfile {
|
||||
export interface SnAccountProfile {
|
||||
id: number
|
||||
accountId: number
|
||||
birthday?: Date | null
|
||||
@ -50,7 +50,7 @@ interface SnAccountProfile {
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
interface SnAccountBadge {
|
||||
export interface SnAccountBadge {
|
||||
id: number
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
|
Loading…
Reference in New Issue
Block a user