[feat] fix auth, add UserProfile + CreateTeam + TeamCard

This commit is contained in:
cue
2024-04-01 11:24:03 +03:00
parent e3de361f8c
commit 910c0753af
12 changed files with 383 additions and 19 deletions
+6
View File
@@ -0,0 +1,6 @@
// export const API_BASE = "http://158.160.56.239:8080/api/"
// export const API_BASE = "http://212.22.79.188:9090/api/" //2 сервер
export const API_BASE = "http://localhost:8080/api/" //3 сервер
export const API_REG = "registration/"
export const API_CREATE_TOKEN = "token/"
@@ -13,7 +13,6 @@
font-weight: 900; font-weight: 900;
font-size: 16px; font-size: 16px;
line-height: 100%; line-height: 100%;
color: #000;
} }
.input-search{ .input-search{
border: 0; border: 0;
@@ -0,0 +1,39 @@
@icon-size: 256px;
.user-icon{
margin: 20px;
width: @icon-size;
height: @icon-size;
border-radius: 200px;
background-color: #222222;
border: 2px #3c3c3c solid;
}
.username{
color: #828282;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-weight: lighter;
font-weight: 200;
font-size: 24px;
}
.card{
margin: 20px;
padding: 10px;
width: calc(100% - 20px);
}
.info-line{
display: flex;
}
.h1{
font-size: 36px;
}
.p{
font-size: 16px;
color: #d3d3d3;
}
@@ -0,0 +1,41 @@
import { Separator } from "../../shared/ui/separator";
import { Card } from "../../shared/ui/card";
import less from "./UserProfile.module.less"
import { PanelRightDashedIcon, Pointer, PointerOff } from "lucide-react";
const UserProfile = () => {
return (
<section className="flex flex-row">
<div className="fle flex-clow">
<div><img className={less["user-icon"]} src="./" alt="user-icon" /></div>
<h2 className={less["username"]}>username</h2>
<Separator />
<div className={less["info-line"]}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M3 2.25a.75.75 0 0 0 0 1.5v16.5h-.75a.75.75 0 0 0 0 1.5H15v-18a.75.75 0 0 0 0-1.5H3ZM6.75 19.5v-2.25a.75.75 0 0 1 .75-.75h3a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-.75.75h-3a.75.75 0 0 1-.75-.75ZM6 6.75A.75.75 0 0 1 6.75 6h.75a.75.75 0 0 1 0 1.5h-.75A.75.75 0 0 1 6 6.75ZM6.75 9a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75ZM6 12.75a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 0 1.5h-.75a.75.75 0 0 1-.75-.75ZM10.5 6a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75Zm-.75 3.75A.75.75 0 0 1 10.5 9h.75a.75.75 0 0 1 0 1.5h-.75a.75.75 0 0 1-.75-.75ZM10.5 12a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75ZM16.5 6.75v15h5.25a.75.75 0 0 0 0-1.5H21v-12a.75.75 0 0 0 0-1.5h-4.5Zm1.5 4.5a.75.75 0 0 1 .75-.75h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75h-.008a.75.75 0 0 1-.75-.75v-.008Zm.75 2.25a.75.75 0 0 0-.75.75v.008c0 .414.336.75.75.75h.008a.75.75 0 0 0 .75-.75v-.008a.75.75 0 0 0-.75-.75h-.008ZM18 17.25a.75.75 0 0 1 .75-.75h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75h-.008a.75.75 0 0 1-.75-.75v-.008Z" clipRule="evenodd" />
</svg>
<p>Город</p> <p>Москва</p></div>
<div className={less["info-line"]}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="m11.54 22.351.07.04.028.016a.76.76 0 0 0 .723 0l.028-.015.071-.041a16.975 16.975 0 0 0 1.144-.742 19.58 19.58 0 0 0 2.683-2.282c1.944-1.99 3.963-4.98 3.963-8.827a8.25 8.25 0 0 0-16.5 0c0 3.846 2.02 6.837 3.963 8.827a19.58 19.58 0 0 0 2.682 2.282 16.975 16.975 0 0 0 1.145.742ZM12 13.5a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" clipRule="evenodd" />
</svg>
<p>Город</p> <p>Москва</p></div>
<div className={less["info-line"]}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path d="M4.913 2.658c2.075-.27 4.19-.408 6.337-.408 2.147 0 4.262.139 6.337.408 1.922.25 3.291 1.861 3.405 3.727a4.403 4.403 0 0 0-1.032-.211 50.89 50.89 0 0 0-8.42 0c-2.358.196-4.04 2.19-4.04 4.434v4.286a4.47 4.47 0 0 0 2.433 3.984L7.28 21.53A.75.75 0 0 1 6 21v-4.03a48.527 48.527 0 0 1-1.087-.128C2.905 16.58 1.5 14.833 1.5 12.862V6.638c0-1.97 1.405-3.718 3.413-3.979Z" />
<path d="M15.75 7.5c-1.376 0-2.739.057-4.086.169C10.124 7.797 9 9.103 9 10.609v4.285c0 1.507 1.128 2.814 2.67 2.94 1.243.102 2.5.157 3.768.165l2.782 2.781a.75.75 0 0 0 1.28-.53v-2.39l.33-.026c1.542-.125 2.67-1.433 2.67-2.94v-4.286c0-1.505-1.125-2.811-2.664-2.94A49.392 49.392 0 0 0 15.75 7.5Z" />
</svg>
<p>telegram</p> <p>@wolf</p></div>
<div className={less["info-line"]}></div>
</div>
<div className="fle flex-clow">
</div>
<Card className={less.card}>
<h1 className={less.h1}>Имя Фамилия</h1>
<Separator />
<p className={less.p}></p>
</Card>
</section>
)
}
export default UserProfile;
@@ -1,9 +1,16 @@
import TeamCard from "../../widgets/TeamCard/TeamCard";
import UserProfile from "../../features/UserProfile/UserProfile";
import less from "./MyTeams.module.less" import less from "./MyTeams.module.less"
import CreateTeam from "../../widgets/CreateTeam/CreateTeam";
const MyTeams = () => { const MyTeams = () => {
return ( return (
<p>My teams</p> <>
<UserProfile />
<TeamCard/>
<CreateTeam/>
</>
) )
} }
export default MyTeams; export default MyTeams;
+140
View File
@@ -0,0 +1,140 @@
"use client"
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { Cross2Icon } from "@radix-ui/react-icons"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "../../../../lib/utils"
const Sheet = SheetPrimitive.Root
const SheetTrigger = SheetPrimitive.Trigger
const SheetClose = SheetPrimitive.Close
const SheetPortal = SheetPrimitive.Portal
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
)
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
SheetHeader.displayName = "SheetHeader"
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
SheetFooter.displayName = "SheetFooter"
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
))
SheetTitle.displayName = SheetPrimitive.Title.displayName
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
SheetDescription.displayName = SheetPrimitive.Description.displayName
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
}
@@ -0,0 +1,28 @@
import { Textarea } from "../../shared/ui/textarea";
import { Input } from "../../shared/ui/input";
import { SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, Sheet } from "../../shared/ui/sheet";
import less from "./CreateTeam.module.less"
import { Button } from "../../shared/ui/button";
const CreateTeam = () =>{
return(
<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetContent className="w-[400px] sm:w-[540px]">
<SheetHeader>
<SheetTitle>Создание команды</SheetTitle>
<SheetDescription>
Тут вы можете создать свою команду для участия, к примеру.... в хакатонах
<Input placeholder="Название"></Input>
<Input type="number" placeholder="Возрастное ограничение"></Input>
<Textarea placeholder="Описание"></Textarea>
<Button>Создать команду</Button>
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
)
}
export default CreateTeam;
@@ -1,42 +1,67 @@
import { FormEvent } from "react"; import { FormEvent } from "react";
import { API_BASE, API_CREATE_TOKEN, API_REG } from "../../app/APIurl";
//логин
export const submitLogin = (e: FormEvent<HTMLFormElement>) => { export const submitLogin = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
const formData = new FormData(e.currentTarget); const formData = new FormData(e.currentTarget);
const formProps = Object.fromEntries(formData); const formProps = Object.fromEntries(formData);
console.log(formProps) console.log(formProps)
fetch(`${API_BASE}${API_CREATE_TOKEN}`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(formProps)
})
.then(response => {
console.log(response.status);
if (response.ok) {
console.log('Создан:', response.headers.get('Location'));
return response.json();
} else {
throw new Error('Код ошибки: ' + response.status);
}
})
.then(data => {
console.log('Успешно:', data);
})
.catch(error => {
console.error('Возникла ошибка с логином4:', error);
});
} }
//регистрация
export const submitRegister = (e: FormEvent<HTMLFormElement>) => { export const submitRegister = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
const formData = new FormData(e.currentTarget); const formData = new FormData(e.currentTarget);
const formProps = Object.fromEntries(formData); const formProps = Object.fromEntries(formData);
console.log(formProps)
const apiUrl = "http://localhost:8080/api/registration/";
fetch(apiUrl, { fetch(`${API_BASE}${API_REG}`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
body: formData body: JSON.stringify(formProps)
}) })
.then(response => { .then(response => {
console.log(response.status) console.log(response.status);
if (response.status === 201) { if (response.ok) {
console.log('Создан:', response.headers.get('Location')); console.log('Создан:', response.headers.get('Location'));
} else if (!(response.status === 201)) { return response.json();
throw new Error('Код ошибки: ' + response.status); } else {
throw new Error('Код ошибки: ' + response.status);
} }
return response.json(); })
}) .then(data => {
.then(data => {
console.log('Успешно:', data); console.log('Успешно:', data);
}) })
.catch(error => { .catch(error => {
console.error('Возникла ошибка с регой:', error); console.error('Возникла ошибка с регой:', error);
}); });
} }
@@ -21,7 +21,7 @@ const AuthForm = () => {
</TabsList> </TabsList>
<TabsContent value="account" > <TabsContent value="account" >
<form className="flex flex-col gap-y-1" onSubmit={submitLogin}> <form className="flex flex-col gap-y-1" onSubmit={submitLogin}>
<Input type="email" name="email" placeholder="Email" /> <Input type="text" name="username" placeholder="Username" />
<Input type="password" name="password" placeholder="Password" /> <Input type="password" name="password" placeholder="Password" />
<Button className="mt-3">{t("buttonLoginInSystem")}</Button> <Button className="mt-3">{t("buttonLoginInSystem")}</Button>
</form> </form>
@@ -0,0 +1,39 @@
@icon-size: 256px;
.user-icon{
margin: 20px;
width: @icon-size;
height: @icon-size;
border-radius: 0px;
background-color: #222222;
border: 2px #3c3c3c solid;
}
.username{
color: #828282;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-weight: lighter;
font-weight: 200;
font-size: 24px;
}
.card{
margin: 20px;
padding: 10px;
width: calc(100% - 20px);
}
.info-line{
display: flex;
}
.h1{
font-size: 36px;
}
.p{
font-size: 16px;
color: #d3d3d3;
}
@@ -0,0 +1,40 @@
import { Card } from "../../shared/ui/card";
import less from "./TeamCard.module.less"
import { Separator } from "../../shared/ui/separator";
import { Button } from "../../shared/ui/button";
const TeamCard = () => {
return(
<section className="flex flex-row">
<div className="fle flex-clow">
<div><img className={less["user-icon"]} src="./" alt="user-icon" /></div>
<div className={less["info-line"]}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M3 2.25a.75.75 0 0 0 0 1.5v16.5h-.75a.75.75 0 0 0 0 1.5H15v-18a.75.75 0 0 0 0-1.5H3ZM6.75 19.5v-2.25a.75.75 0 0 1 .75-.75h3a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-.75.75h-3a.75.75 0 0 1-.75-.75ZM6 6.75A.75.75 0 0 1 6.75 6h.75a.75.75 0 0 1 0 1.5h-.75A.75.75 0 0 1 6 6.75ZM6.75 9a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75ZM6 12.75a.75.75 0 0 1 .75-.75h.75a.75.75 0 0 1 0 1.5h-.75a.75.75 0 0 1-.75-.75ZM10.5 6a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75Zm-.75 3.75A.75.75 0 0 1 10.5 9h.75a.75.75 0 0 1 0 1.5h-.75a.75.75 0 0 1-.75-.75ZM10.5 12a.75.75 0 0 0 0 1.5h.75a.75.75 0 0 0 0-1.5h-.75ZM16.5 6.75v15h5.25a.75.75 0 0 0 0-1.5H21v-12a.75.75 0 0 0 0-1.5h-4.5Zm1.5 4.5a.75.75 0 0 1 .75-.75h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75h-.008a.75.75 0 0 1-.75-.75v-.008Zm.75 2.25a.75.75 0 0 0-.75.75v.008c0 .414.336.75.75.75h.008a.75.75 0 0 0 .75-.75v-.008a.75.75 0 0 0-.75-.75h-.008ZM18 17.25a.75.75 0 0 1 .75-.75h.008a.75.75 0 0 1 .75.75v.008a.75.75 0 0 1-.75.75h-.008a.75.75 0 0 1-.75-.75v-.008Z" clipRule="evenodd" />
</svg>
<p>Город</p> <p>Москва</p></div>
<div className={less["info-line"]}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="m11.54 22.351.07.04.028.016a.76.76 0 0 0 .723 0l.028-.015.071-.041a16.975 16.975 0 0 0 1.144-.742 19.58 19.58 0 0 0 2.683-2.282c1.944-1.99 3.963-4.98 3.963-8.827a8.25 8.25 0 0 0-16.5 0c0 3.846 2.02 6.837 3.963 8.827a19.58 19.58 0 0 0 2.682 2.282 16.975 16.975 0 0 0 1.145.742ZM12 13.5a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" clipRule="evenodd" />
</svg>
<p>Город</p> <p>Москва</p></div>
<div className={less["info-line"]}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6">
<path fillRule="evenodd" d="M10.5 3.798v5.02a3 3 0 0 1-.879 2.121l-2.377 2.377a9.845 9.845 0 0 1 5.091 1.013 8.315 8.315 0 0 0 5.713.636l.285-.071-3.954-3.955a3 3 0 0 1-.879-2.121v-5.02a23.614 23.614 0 0 0-3 0Zm4.5.138a.75.75 0 0 0 .093-1.495A24.837 24.837 0 0 0 12 2.25a25.048 25.048 0 0 0-3.093.191A.75.75 0 0 0 9 3.936v4.882a1.5 1.5 0 0 1-.44 1.06l-6.293 6.294c-1.62 1.621-.903 4.475 1.471 4.88 2.686.46 5.447.698 8.262.698 2.816 0 5.576-.239 8.262-.697 2.373-.406 3.092-3.26 1.47-4.881L15.44 9.879A1.5 1.5 0 0 1 15 8.818V3.936Z" clipRule="evenodd" />
</svg>
<p>18+</p> </div>
<div className={less["info-line"]}></div>
</div>
<div className="fle flex-clow">
</div>
<Card className={less.card}>
<h1 className={less.h1}>Организация</h1>
<Separator />
<Button>Запросить членство</Button>
</Card>
</section>)
}
export default TeamCard;