Commit 4f7e1d0b authored by Wellton Quirino's avatar Wellton Quirino

crud of areas

parent 9863ab2f
This diff is collapsed.
import { api } from '@/lib/axios'
interface FileBanner {
name: string
}
export type AreasProps = {
id: string
name: string
desktopBanner?: { [key: string]: FileBanner }
mobileBanner?: { [key: string]: FileBanner }
}
export async function createAreas({
name,
desktopBanner,
mobileBanner,
}: AreasProps) {
const area = await api.post<AreasProps[]>('/areas', {
name,
desktopBanner,
mobileBanner,
})
return area
}
export async function editArea({
id,
name,
desktopBanner,
mobileBanner,
}: AreasProps) {
const area = await api.patch<AreasProps[]>(`/areas/${id}`, {
name,
desktopBanner,
mobileBanner,
})
return area
}
export async function getAreas() {
const areas = await api.get<AreasProps[]>('/areas')
return areas
}
export async function getAreasId(id: string) {
const area = await api.get<AreasProps>(`/areas/${id}`)
return area
}
export async function deleteArea(id: string) {
const area = await api.delete(`/areas/${id}`)
return area
}
\ No newline at end of file
import { api } from '@/lib/axios'
export type AudiencesProps = {
id: string
name: string
}
export async function getAudiences() {
const audiences = await api.get<AudiencesProps[]>('/audiences')
return audiences
}
import { api } from '@/lib/axios'
export type BannersProps = {
id: string
name: string
desktopBanner?: string
mobileBanner?: string
}
export async function getBanners() {
const banners = await api.get<BannersProps[]>('/banners')
return banners
}
import { StyledInputs } from '@/components/mui/styled-inputs'
'use client'
import { AreasProps, deleteArea, editArea, getAreasId } from '@/api/areas'
import BreadcrumbComponent from '@/components/breadcrumb-component'
import InputFile from '@/components/input-file'
import ModalDialog from '@/components/modal-dialog'
import { AlertDialog, AlertDialogTrigger } from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import { TextField } from '@mui/material'
import { Input } from '@/components/ui/input'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { Trash } from 'lucide-react'
import { useParams, useRouter } from 'next/navigation'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
export default function AreaId() {
const params = useParams<{ id: string }>()
const { register, handleSubmit, watch } = useForm<AreasProps>()
const router = useRouter()
const data = watch()
const valueDesktopBanner = data?.desktopBanner?.['0']?.name
const valueMobileBanner = data?.mobileBanner?.['0']?.name
const queryClient = useQueryClient()
const { data: area, isLoading, isPending } = useQuery({
queryKey: ['area'],
queryFn: () => getAreasId(params.id),
enabled: !!params.id,
})
const mutationEdit = useMutation({
mutationFn: editArea,
onSuccess: () => {
toast.success('Área editada com sucesso!')
queryClient.invalidateQueries({ queryKey: ['areas'] })
router.push('/admin')
},
})
const mutationDelete = useMutation({
mutationFn: deleteArea,
onSuccess: () => {
toast.success('Área deletada com sucesso!')
queryClient.invalidateQueries({ queryKey: ['areas'] })
router.push('/admin')
},
})
function onSubmit(data: AreasProps) {
const body = {
...data,
id: params.id,
}
mutationEdit.mutate(body)
}
function handleDeleteArea() {
mutationDelete.mutate(params.id)
}
if(isLoading) {
console.log('isloading')
return <span>isLoading TEST...</span>
}
if(isPending) {
console.log('isPeding')
return <span>isPending TEST...</span>
}
return (
<section className="container py-10">
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Editar Área</h1>
<Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
<Button
variant="ghost"
className="uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
>
<span>Apagar área</span>
<Trash />
</Button>
</div>
<div className="w-full">
<TextField
label="Nome da área"
variant="standard"
type="text"
className="flex"
sx={StyledInputs({ color: '#26AAA7' })}
/>
<div className="flex justify-between flex-wrap gap-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
<section className="container py-20 space-y-10">
<BreadcrumbComponent />
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex items-center gap-6">
<h1 className="text-3xl font-bold">Editar Área</h1>
<Button variant="secondary" type='submit' className="uppercase rounded-sm">
Salvar e publicar
</Button>
<AlertDialog>
<>
<AlertDialogTrigger
className="uppercase flex items-center gap-2 text-orange-100 border-none hover:bg-orange-100/10 hover:text-orange-100 h-10 px-5 rounded-sm"
type="button"
>
<span>Apagar área</span>
<Trash />
</AlertDialogTrigger>
<ModalDialog
title="Tem certeza que deseja deletar a área?"
description={`Ao clicar em continue você irá deletar a área ${area?.data.name}`}
handleClick={handleDeleteArea}
/>
</>
</AlertDialog>
</div>
<div className="w-full mt-16">
<Input
label="Nome da área"
className="border-green-400"
defaultValue={area?.data.name}
{...register('name')}
type="text"
/>
<div className="flex justify-between flex-wrap gap-6 py-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: 1512 x 300</span>
<span>Formatos aceitos: .png, .jpg</span>
<InputFile
id="desktopBanner"
values={valueDesktopBanner}
label="Adicionar banner"
{...register('desktopBanner')}
/>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: 390 x 300</span>
<span>Formatos aceitos: .png, .jpg</span>
<InputFile
id="mobileBanner"
values={valueMobileBanner}
label="Adicionar banner"
{...register('mobileBanner')}
/>
</div>
</div>
</div>
</div>
</form>
</section>
)
}
'use client'
import { AreasProps, createAreas } from '@/api/areas'
import InputFile from '@/components/input-file'
import { StyledInputs } from '@/components/mui/styled-inputs'
import { Button } from '@/components/ui/button'
import { TextField } from '@mui/material'
import { Trash } from 'lucide-react'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useRouter } from 'next/navigation'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
export default function Area() {
const { register, handleSubmit, watch } = useForm<AreasProps>()
const router = useRouter()
const data = watch()
const valueDesktopBanner = data?.desktopBanner?.['0']?.name
const valueMobileBanner = data?.mobileBanner?.['0']?.name
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: createAreas,
onSuccess: () => {
toast.success('Área criada com sucesso!')
queryClient.invalidateQueries({ queryKey: ['areas'] })
router.push('/admin')
},
})
function onSubmit(data: AreasProps) {
mutation.mutate(data)
}
return (
<section className="container py-10">
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Criar Área</h1>
<Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
<Button
variant="ghost"
className="uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
>
<span>Apagar área</span>
<Trash />
</Button>
</div>
<div className="w-full">
<TextField
label="Nome da área"
variant="standard"
type="text"
className="flex"
sx={StyledInputs({ color: '#26AAA7' })}
/>
<div className="flex justify-between flex-wrap gap-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: </span>
<span>Formatos aceitos: .png, .jpg</span>
<Button
variant="third"
className="border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
>
Adicionar banner
</Button>
<section className="container py-20 space-y-10">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="flex items-center gap-6">
<h1 className="text-3xl font-bold">Criar Área</h1>
<Button variant="secondary" className="uppercase rounded-sm">
Salvar e publicar
</Button>
</div>
<div className="w-full mt-16">
<TextField
label="Nome da área"
variant="standard"
type="text"
className="flex"
{...register('name')}
sx={StyledInputs({ color: '#26AAA7' })}
/>
<div className="flex justify-between flex-wrap gap-6 py-6">
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Desktop</h6>
<span className="mt-4">Dimensões recomendadas: 1512 x 300</span>
<span>Formatos aceitos: .png, .jpg</span>
<InputFile
id="desktopBanner"
values={valueDesktopBanner}
label="Adicionar banner"
{...register('desktopBanner')}
/>
</div>
<div className="flex flex-col flex-1 mt-6">
<h6 className="text-xl text-purple-100">Banner Mobile</h6>
<span className="mt-4">Dimensões recomendadas: 390 x 300</span>
<span>Formatos aceitos: .png, .jpg</span>
<InputFile
id="mobileBanner"
values={valueMobileBanner}
label="Adicionar banner"
{...register('mobileBanner')}
/>
</div>
</div>
</div>
</div>
</form>
</section>
)
}
......@@ -30,9 +30,9 @@ export default function EditCourse() {
<form>
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Editar curso</h1>
<Button variant="third" className="uppercase">
{/* <Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
</Button> */}
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
......
......@@ -30,9 +30,9 @@ export default function Curso() {
<form>
<div className="flex items-center gap-6">
<h1 className="text-green-700 text-3xl font-bold">Criar curso</h1>
<Button variant="third" className="uppercase">
{/* <Button variant="third" className="uppercase">
Salvar como rascunho
</Button>
</Button> */}
<Button variant="secondary" className="uppercase">
Salvar e publicar
</Button>
......
'use client'
import { getAreas } from '@/api/areas'
import { Card } from '@/components/card'
import { InputMui } from '@/components/mui/inputs'
import { Button } from '@/components/ui/button'
import { CoursesCard } from '@/utils/courses-array'
import { useQuery } from '@tanstack/react-query'
import { Pencil, Search } from 'lucide-react'
import Link from 'next/link'
const areas = [
{
id: '1',
title: 'Educação',
},
{
id: '2',
title: 'Negócios',
},
{
id: '3',
title: 'Comunicação',
},
{
id: '4',
title: 'Saúde',
},
{
id: '5',
title: 'Tecnologia',
},
{
id: '6',
title: 'Teologia',
},
]
// const areas = [
// {
// id: '1',
// title: 'Educação',
// },
// {
// id: '2',
// title: 'Negócios',
// },
// {
// id: '3',
// title: 'Comunicação',
// },
// {
// id: '4',
// title: 'Saúde',
// },
// {
// id: '5',
// title: 'Tecnologia',
// },
// {
// id: '6',
// title: 'Teologia',
// },
// ]
const banners = [
{
......@@ -42,6 +46,21 @@ const banners = [
]
export default function Admin() {
const {
data: areas,
error,
isLoading,
isError,
} = useQuery({ queryKey: ['areas'], queryFn: getAreas })
if (isLoading) {
return <span>Loading...</span>
}
if (isError) {
return <span>Error: {error.message}</span>
}
return (
<section className="container">
<h1 className="text-green-400 text-2xl">Bem vindo, João da Silva,</h1>
......@@ -55,13 +74,13 @@ export default function Admin() {
<nav className="my-6">
<ul className="space-y-4">
{areas.map((area) => (
<li key={area.title} className="border-b border-green-400">
{areas?.data.map((area) => (
<li key={area.id} className="border-b border-green-400">
<Link
href={`/admin/area/${area.id}`}
className="flex justify-between py-2 hover:bg-green-400/10"
>
<span>{area.title}</span>
<span>{area.name}</span>
<Pencil className="text-green-400" />
</Link>
</li>
......
......@@ -5,6 +5,9 @@ import '@/styles/globals.css'
import { StyledEngineProvider } from '@mui/material'
import type { Metadata } from 'next'
import { Poppins } from 'next/font/google'
import { Toaster } from 'sonner'
import ReactQueryProvider from '@/providers/react-query'
const poppins = Poppins({ subsets: ['latin'], weight: ['300', '400', '800'] })
......@@ -28,9 +31,12 @@ export default function RootLayout({
disableTransitionOnChange
>
<StyledEngineProvider injectFirst>
<Header />
{children}
<Footer />
<ReactQueryProvider>
<Toaster richColors />
<Header />
{children}
<Footer />
</ReactQueryProvider>
</StyledEngineProvider>
</ThemeProvider>
</body>
......
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import Link from "next/link"
export default function BreadcrumbComponent() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/admin">
Admin
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Área</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}
import { forwardRef } from 'react'
interface InputFileProps extends React.InputHTMLAttributes<HTMLInputElement> {
id: string
values?: string
label: string
}
const InputFile = forwardRef<HTMLInputElement, InputFileProps>(
({ id, values, label, ...inputProps }, ref) => {
return (
<label
htmlFor={id}
className="flex justify-center items-center border border-dotted rounded-sm border-green-400 bg-green-400/10 cursor-pointer hover:bg-green-400/5 text-green-400 text-sm h-10 mt-6"
>
{values || label}
<input
id={id}
type="file"
className="hidden"
ref={ref}
{...inputProps}
/>
</label>
)
},
)
InputFile.displayName = 'InputFile'
export default InputFile
import {
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from './ui/alert-dialog'
type AlertDialogProps = {
title: string
description: string
handleClick: () => void
}
export default function ModalDialog({
title,
description,
handleClick,
}: AlertDialogProps) {
return (
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{title}</AlertDialogTitle>
<AlertDialogDescription>{description}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancelar</AlertDialogCancel>
<AlertDialogAction onClick={handleClick}>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
)
}
"use client"
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
const AlertDialog = AlertDialogPrimitive.Root
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
const AlertDialogPortal = AlertDialogPrimitive.Portal
const AlertDialogOverlay = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.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}
/>
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
/>
</AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
const AlertDialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
AlertDialogHeader.displayName = "AlertDialogHeader"
const AlertDialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
AlertDialogFooter.displayName = "AlertDialogFooter"
const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold", className)}
{...props}
/>
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName
const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action
ref={ref}
className={cn(buttonVariants(), className)}
{...props}
/>
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: "outline" }),
"mt-2 sm:mt-0",
className
)}
{...props}
/>
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
export {
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
}
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { ChevronRight, MoreHorizontal } from "lucide-react"
import { cn } from "@/lib/utils"
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
separator?: React.ReactNode
}
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
Breadcrumb.displayName = "Breadcrumb"
const BreadcrumbList = React.forwardRef<
HTMLOListElement,
React.ComponentPropsWithoutRef<"ol">
>(({ className, ...props }, ref) => (
<ol
ref={ref}
className={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
className
)}
{...props}
/>
))
BreadcrumbList.displayName = "BreadcrumbList"
const BreadcrumbItem = React.forwardRef<
HTMLLIElement,
React.ComponentPropsWithoutRef<"li">
>(({ className, ...props }, ref) => (
<li
ref={ref}
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
))
BreadcrumbItem.displayName = "BreadcrumbItem"
const BreadcrumbLink = React.forwardRef<
HTMLAnchorElement,
React.ComponentPropsWithoutRef<"a"> & {
asChild?: boolean
}
>(({ asChild, className, ...props }, ref) => {
const Comp = asChild ? Slot : "a"
return (
<Comp
ref={ref}
className={cn("transition-colors hover:text-foreground", className)}
{...props}
/>
)
})
BreadcrumbLink.displayName = "BreadcrumbLink"
const BreadcrumbPage = React.forwardRef<
HTMLSpanElement,
React.ComponentPropsWithoutRef<"span">
>(({ className, ...props }, ref) => (
<span
ref={ref}
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
))
BreadcrumbPage.displayName = "BreadcrumbPage"
const BreadcrumbSeparator = ({
children,
className,
...props
}: React.ComponentProps<"li">) => (
<li
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRight />}
</li>
)
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
const BreadcrumbEllipsis = ({
className,
...props
}: React.ComponentProps<"span">) => (
<span
role="presentation"
aria-hidden="true"
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">More</span>
</span>
)
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
}
import { cva, VariantProps } from 'class-variance-authority'
import * as React from 'react'
import { cn } from '@/lib/utils'
const inputVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-ring focus-visible:border-b-2 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none disabled:cursor-not-allowed',
{
variants: {
variant: {
default:
'flex h-10 w-full border border-t-0 border-x-0 border-gray-300 px-2 py-2 text-md text-white bg-transparent file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-300',
secondary:
'text-gray-50 bg-gradient-to-r from-purple-100 to-purple-200 hover:bg-purple-200 hover:opacity-75',
file: 'border border-dotted rounded-sm border-green-400 bg-green-400/10 cursor-pointer hover:bg-green-400/5 text-green-400 text-sm h-10',
destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
ghost:
'dark:hover:bg-white/10 dark:hover:text-gray-50 hover:bg-gray-900/10',
link: 'text-primary underline-offset-4 hover:underline',
},
},
defaultVariants: {
variant: 'default',
},
},
)
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
extends React.InputHTMLAttributes<HTMLInputElement>,
VariantProps<typeof inputVariants> {
label?: string
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
({ className, variant, type, label, ...props }, ref) => {
return (
<input
type={type}
className={cn(
'flex h-10 w-full border border-t-0 border-x-0 border-gray-300 px-2 py-2 text-md text-white ile:border-0 bg-transparent file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-300 focus-visible:outline-none focus-visible:border-b-white focus-visible:border-b-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
ref={ref}
{...props}
/>
<label>
<span className="text-sm text-gray-400">{label}</span>
<input
type={type}
className={cn(inputVariants({ variant, className }))}
ref={ref}
{...props}
/>
</label>
)
},
)
Input.displayName = 'Input'
export { Input }
export { Input, inputVariants }
import axios from 'axios'
export const api = axios.create({
baseURL: '/api',
baseURL: 'http://localhost:3000',
})
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactNode } from 'react'
type ReactQueryProps = {
children: ReactNode
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
})
export default function ReactQueryProvider({ children }: ReactQueryProps) {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment