/
durovcode
/
Frontend
Обзор
Документация
Войти
/
durovcode
/
Frontend
Код
Запросы
0
Задачи
Пакеты
0
Релизы
0
Аналитика
master
src/pages/profile.tsx
344 строки
13 KB
Alch3m1st
Correction placeholder, add text verification.
22 сен 2024, 06:38
22 сен 2024, 06:38
a548aca
Код
Авторство
О чём код?
"use client" import { Avatar, AvatarFallback, AvatarImage, } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion" import { Binoculars, Paperclip, Search, File, Bolt, BookOpenText, Star, ChartPie, PenTool, Sparkle, GraduationCap, MessagesSquare } from "lucide-react" import { ProfileSettingsDrawer } from "@/components/profileSettingsDrawer" import { FileDrawer } from "@/components/fileDrawer" import { PolarAngleAxis, RadialBar, RadialBarChart } from "recharts" import { Card, CardContent } from "@/components/ui/card" import { ChartContainer } from "@/components/ui/chart" import React from "react" import { FileUploadDrawer } from "@/components/fileUploadDrawer" import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'; import { jwtDecode } from 'jwt-decode'; export const Profile = () => { const [role, setRole] = React.useState("student"); const [jwtData, setJwtData] = React.useState({}); React.useEffect(() => { setRole(jwtDecode(localStorage.getItem("jwt"))["rol"]); if (localStorage.getItem("jwt")) { setJwtData( jwtDecode(localStorage.getItem("jwt")) ); console.log(jwtData['rol']); } else { window.location.href = "/auth/" } }, []); return ( <> <div className="flex justify-between items-center p-7 mt-5 mb-5 bg-gray-100 mr-5 ml-5 rounded-2xl"> <div className="flex items-center gap-3"> <UserAvatar></UserAvatar> <div className="flex flex-col gap-1"> <span className="text-2xl font-bold">Павел Дуров</span> <div className="flex gap-2 flex-wrap"> {role === "student" ? ( <> <Badge className="w-fit bg-blue-200 gap-2" variant="secondary"> <BookOpenText className="w-5 h-5" /> Студент </Badge> </> ) : ( <> <Badge className="w-fit bg-blue-200 gap-2" variant="secondary"> <GraduationCap className="w-5 h-5" /> Преподаватель </Badge> </> )} </div> </div> </div> <ProfileSettingsDrawer></ProfileSettingsDrawer> </div> <Link to="/chat/"> <div className="flex justify-center items-center gap-5 p-7 mt-5 mb-5 mr-5 ml-5 rounded-2xl bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500"> <MessagesSquare className="h-7 w-7 text-white rotate-12" /> <span className="text-white text-lg font-bold">Чат с ассистентом</span> </div> </Link> {role === "student" ? ( <> <div className="bg-gray-100 mr-5 p-5 ml-5 rounded-2xl mb-5"> <div className="flex flex-col items-center gap-3 text-center mt-5"> <PenTool className="w-10 h-10" /> <span className="text-2xl font-semibold leading-none tracking-tight">Панель инструментов</span> </div> <ToolsPanel></ToolsPanel> </div> <div className="bg-gray-100 mr-5 p-5 ml-5 rounded-2xl mb-20"> <div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center gap-3 text-center"> <ChartPie className="w-10 h-10" /> <span className="text-2xl font-semibold leading-none tracking-tight">Твоя статистика</span> </div> <br /> <Widget></Widget> </div> </div> <FileUploadDrawer triggerComponent={ <div className="w-15 h-15 fixed bottom-5 p-4 left-1/2 transform -translate-x-1/2 bg-blue-500 hover:bg-blue-600 text-white rounded-full cursor-pointer"> <Sparkle /> </div> }></FileUploadDrawer> </> ) : ( <> <div className="bg-gray-100 mr-5 p-5 ml-5 rounded-2xl mb-5"> <div className="flex flex-col items-center gap-3 text-center mt-5"> <GraduationCap className="w-10 h-10" /> <span className="text-2xl font-semibold leading-none tracking-tight">Прикреплённые студенты</span> </div> <StudentsPanel></StudentsPanel> </div> </> )} </> ) } export const UserAvatar = () => { return ( <> <Avatar className="w-[80px] h-[80px] border-white border-8"> <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /> <AvatarFallback className="text-4xl font-black">UR</AvatarFallback> </Avatar> </> ) } export const ToolsPanel = () => { return ( <> <div className="p-3 rounded-2xl mt-5"> <Accordion type="single" collapsible className="w-full"> <AccordionItem value="item-1"> <AccordionTrigger> <div className="flex items-center gap-3"> <Paperclip /> Обработанные файлы </div> </AccordionTrigger> <AccordionContent> <div className="flex gap-2 flex-wrap"> <FileBlock filename={"file_1"}></FileBlock> <FileBlock filename={"file_2"}></FileBlock> </div> </AccordionContent> </AccordionItem> <AccordionItem value="item-2"> <AccordionTrigger> <div className="flex items-center gap-3"> <Sparkle /> Последние пожелания </div> </AccordionTrigger> <AccordionContent> <div className="flex flex-col gap-3"> <div className="relative rounded bg-gray-300 px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"> Не проверяй параграфы. Мне это ни к чему. </div> <div className="relative rounded bg-gray-300 px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"> Выдели ошибки в формировании причастных оборотов. </div> </div> </AccordionContent> </AccordionItem> <AccordionItem value="item-3"> <AccordionTrigger> <div className="flex items-center gap-3"> <Search /> Ещё что-то </div> </AccordionTrigger> <AccordionContent> Yes. It's animated by default, but you can disable it if you prefer. </AccordionContent> </AccordionItem> </Accordion> </div> </> ) } export const Widget = () => { return ( <Card className="w-full"> <CardContent className="flex gap-4 p-4"> <div className="grid items-center gap-2"> <div className="grid flex-1 auto-rows-min gap-0.5"> <div className="text-sm text-muted-foreground">Количество исправлений</div> <div className="flex items-baseline gap-1 text-xl font-bold tabular-nums leading-none"> 67/120 <span className="text-sm font-normal text-muted-foreground"> исп. </span> </div> </div> <div className="grid flex-1 auto-rows-min gap-0.5"> <div className="text-sm text-muted-foreground">Кол-во исключительно правильных работ</div> <div className="flex items-baseline gap-1 text-xl font-bold tabular-nums leading-none"> 3/5 <span className="text-sm font-normal text-muted-foreground"> min </span> </div> </div> </div> <ChartContainer config={{ move: { label: "Move", color: "hsl(var(--chart-1))", }, exercise: { label: "Exercise", color: "hsl(var(--chart-2))", } }} className="mx-auto aspect-square w-full max-w-[80%]" > <RadialBarChart margin={{ left: -10, right: -10, top: -10, bottom: -10, }} data={[ { activity: "stand", value: (8 / 12) * 100, fill: "var(--color-stand)", }, { activity: "exercise", value: (46 / 60) * 100, fill: "var(--color-exercise)", }, ]} innerRadius="20%" barSize={24} startAngle={90} endAngle={450} > <PolarAngleAxis type="number" domain={[0, 100]} dataKey="value" tick={false} /> <RadialBar dataKey="value" background cornerRadius={5} /> </RadialBarChart> </ChartContainer> </CardContent> </Card> ) } export const FileBlock = ({ filename }) => { return ( <> <FileDrawer fileComponent={ <> <div className="border-gray-200 border w-fit rounded-xl p-2 flex items-center justify-center text-center gap-2"> <File className="w-5 h-5" /> {filename}.docx </div> </> }> </FileDrawer> </> ) } export const Student = ({ studentName, files }) => { return ( <> <AccordionTrigger> <div className="flex items-center gap-3"> {studentName} </div> </AccordionTrigger> <AccordionContent> <div className="flex gap-2 flex-wrap"> {Array.from(files).map((item, index) => ( <FileBlock key={index} /> ))} </div> </AccordionContent> </> ) } const testStudents = [ { "name": "Виктор Лесин", "files": [ <FileBlock />, <FileBlock />, <FileBlock /> ], }, { "name": "Виктор Лесин", "files": [ <FileBlock />, <FileBlock />, <FileBlock /> ], }, ] export const StudentsPanel = () => { return ( <> <div className="p-3 rounded-2xl mt-5"> <Accordion type="single" collapsible className="w-full"> {Array.from(testStudents).map((item, index) => ( <AccordionItem value={index + 1}> <Student studentName={item.name} files={item.files}></Student> </AccordionItem> ))} </Accordion> </div> </> ) }