feat:add form and table magazine

This commit is contained in:
Anang Yusman 2024-04-17 16:13:29 +07:00
parent 02f27a492e
commit 0bf1aaec3e
10 changed files with 933 additions and 165 deletions

View File

@ -0,0 +1,11 @@
import CreateMagazineForm from '@/components/form/magazine/magazine-form'
import MagazineTable from '@/components/table/magazine/magazine-table'
import React from 'react'
const AdminMagazineCreate = () => {
return (
<div><CreateMagazineForm /></div>
)
}
export default AdminMagazineCreate

View File

@ -0,0 +1,11 @@
import CreateMagazineForm from '@/components/form/magazine/magazine-form'
import MagazineTable from '@/components/table/magazine/magazine-table'
import React from 'react'
const AdminMagazineDetail = () => {
return (
<div><CreateMagazineForm /></div>
)
}
export default AdminMagazineDetail

View File

@ -0,0 +1,10 @@
import MagazineTable from '@/components/table/magazine/magazine-table'
import React from 'react'
const AdminMagazine = () => {
return (
<div><MagazineTable /></div>
)
}
export default AdminMagazine

View File

@ -5,42 +5,6 @@ export default function AdminHumasPage() {
<div className=''>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
</div>
)
}

View File

@ -0,0 +1,261 @@
'use client'
import { Button } from "@nextui-org/button";
import { Card, Checkbox, CheckboxGroup, Divider, Input, Radio, RadioGroup, Select, SelectItem, Slider, Switch, Tab, Table, Tabs, Textarea, User } from "@nextui-org/react";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { TimesIcon } from "@/components/icons";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { close, error, loading } from "@/config/swal";
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import dynamic from 'next/dynamic';
import { useForm } from "react-hook-form";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
export default function CreateMagazineForm() {
const router = useRouter();
const JoditEditor = dynamic(() => import('jodit-react'), { ssr: false });
const MySwal = withReactContent(Swal);
const [isVisible, setIsVisible] = useState(false);
const [tabs, setTabs] = useState<string>("personal-info")
const editor = useRef(null);
const [content, setContent] = useState('');
const handleTab = (tab: any) => {
setTabs(tab);
};
let [files, setFiles] = useState<File[]>([]);
const removeFile = (name: string) => {
const arrayFile: File[] = [];
for (const element of files) {
if (element.name !== name) {
arrayFile.push(element);
}
}
setFiles(arrayFile);
};
const handleFileChange = (event: any) => {
const newFiles: FileList | null = event.target.files;
if (newFiles) {
const allowedExtensions = ['.doc', '.docx', '.pdf', '.ppt', '.pptx', '.xlsx', '.csv'];
let temp: File[] = [...files]; // Salin file-file yang sudah ada
for (let i = 0; i < newFiles.length; i++) {
const file = newFiles[i];
const fileExtension = file.name.split('.').pop()?.toLowerCase();
if (fileExtension && allowedExtensions.includes(`.${fileExtension}`)) {
temp.push(file);
} else {
alert('Format file tidak valid. Hanya file .doc, .docx, .ppt, .pptx, .xlsx, .csv atau .pdf yang diperbolehkan.');
}
}
setFiles(temp);
}
};
const toggleVisibility = () => setIsVisible(!isVisible);
const validationSchema = z.object({
title: z.string().min(1, { message: "Required" }),
slug: z.string().min(1, { message: "Required" }),
});
const formOptions = { resolver: zodResolver(validationSchema) };
type ArticleSchema = z.infer<typeof validationSchema>;
const { register, handleSubmit, formState: { errors }, formState, setValue } = useForm<ArticleSchema>(formOptions);
const save = async (data: any) => {
const request = {
title: data.title,
slug: data.slug,
articleBody: data.articleBody,
status: 1,
};
// loading();
// // const res = await saveManualContext(request);
// if (res.error) {
// error(res.message);
// return false;
// }
close();
successSubmit("/admin/magazine")
}
async function onSubmit(data: any) {
MySwal.fire({
title: "Save Data",
text: "",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#d33",
confirmButtonColor: "#3085d6",
confirmButtonText: "Save",
}).then((result) => {
if (result.isConfirmed) {
save(data);
}
});
}
function successSubmit(redirect: string) {
MySwal.fire({
title: 'Sukses',
icon: 'success',
confirmButtonColor: '#3085d6',
confirmButtonText: 'OK',
}).then((result) => {
if (result.isConfirmed) {
router.push(redirect);
}
});
}
return (
<div className="mx-3 my-5">
<div className="flex flex-col gap-3 mb-4">
<Card className="w-full bg-white">
<div className="w-full mr-2 p-5 ">
<form method="POST" onSubmit={handleSubmit(onSubmit)}>
<>
<div className="flex flex-col gap-1">
<div className="flex flex-row justify-between items-center mt-[24px] gap-3">
<div className="flex flex-col w-6/12">
<Input
type="text"
label="Title"
id="title"
{...register("title")}
placeholder="...."
labelPlacement="outside"
className="w-9/12 font-semibold"
classNames={{
label: "!text-black",
input: "!text-black hover:!text-white focus:!text-white",
inputWrapper: "max-h-[40px] bg-transparant border text-white",
}}
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-small"></span>
</div>
}
/>
{errors.title?.message && (
<p className="text-red-400 text-sm">
{errors.title?.message}
</p>
)}
</div>
<div className="flex flex-col w-6/12">
<Input
type="text"
label="Slug"
id="slug"
{...register("slug")}
placeholder="....."
labelPlacement="outside"
className="w-9/12 font-semibold"
classNames={{
label: "!text-black",
input: "!text-black hover:!text-white focus:!text-white",
inputWrapper: "max-h-[40px] bg-transparant border text-white",
}}
startContent={
<div className="pointer-events-none flex items-center">
<span className="text-default-400 text-small"></span>
</div>
}
/>
{errors.slug?.message && (
<p className="text-red-400 text-sm">
{errors.slug?.message}
</p>
)}
</div>
</div>
<p className="text-sm text-black mt-2 pb-1 pt-3">Upload File (Opsional)</p>
<div className="w-full bg-transparent">
<div className="flex items-center justify-center w-full ">
<label
htmlFor="dropzone-file"
className="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-100 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600"
>
<div className="flex flex-col items-center justify-center pt-5 pb-6 ">
<svg
className="w-10 h-10 mb-3 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
></path>
</svg>
{/* <p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
Drag and drop files here
</p> */}
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
{/* or{" "} */}
<span className="font-semibold underline text-amber-800">
Click to upload
</span>
</p>
</div>
<input id="dropzone-file" type="file" multiple accept=".doc,.docx,.pdf,.ppt,.pptx,.xlsx,.csv" className="hidden" onChange={handleFileChange} />
</label>
</div>
</div>
<p className="text-tiny text-default ">Support file format in word, excel, ppt and pdf</p>
<div className="flex flex-wrap gap-3">
{files?.length > 0 &&
files?.map((list: File) => (
<div key={list.name} className="text-black text-sm py-2 px-4 border-1 border-black w-auto rounded-lg flex justify-between gap-5">
{list.name}
<a className="cursor-pointer" onClick={() => removeFile(list.name)}><TimesIcon /></a>
</div>
))
}
</div>
<div className="mt-1">
<p className="text-black text-sm font-semibold my-2">Description</p>
<JoditEditor
ref={editor}
value={content}
onChange={(newContent) => setContent(newContent)}
className="dark:text-black"
/>
</div>
<div className="flex flex-row gap-3 my-3">
<Link href="/admin/magazine">
<Button
variant="bordered"
className="bg-white border-grey-100 rounded-full text-[#8E5C18] mr-5"
>
Cancel
</Button>{" "}
</Link>
<Button
className="w-[50px]"
color="primary"
size="md"
type="submit">
Submit
</Button>
</div>
</div>
</>
</form>
</div>
</Card>
</div>
</div >
)
}

View File

@ -770,4 +770,138 @@ export const Checklist = ({
</clipPath>
</defs>
</svg>
);
);
export const AddIcon = ({
size,
height = 12,
width = 12,
fill = "none",
...props
}: IconSvgProps) => (
<svg
height={size || height}
width={size || width}
viewBox="0 0 12 12"
fill={fill}
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M5.1665 6.83341H0.166504V5.16675H5.1665V0.166748H6.83317V5.16675H11.8332V6.83341H6.83317V11.8334H5.1665V6.83341Z"
fill="currentColor"
/>
</svg>
);
export const CreateIconIon = ({
size,
height = 24,
width = 24,
fill = "currentColor",
...props
}: IconSvgProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
height={size || height}
width={size || width}
viewBox="0 0 512 512"
{...props}
>
<path
fill="currentColor"
d="M459.94 53.25a16.06 16.06 0 0 0-23.22-.56L424.35 65a8 8 0 0 0 0 11.31l11.34 11.32a8 8 0 0 0 11.34 0l12.06-12c6.1-6.09 6.67-16.01.85-22.38ZM399.34 90L218.82 270.2a9 9 0 0 0-2.31 3.93L208.16 299a3.91 3.91 0 0 0 4.86 4.86l24.85-8.35a9 9 0 0 0 3.93-2.31L422 112.66a9 9 0 0 0 0-12.66l-9.95-10a9 9 0 0 0-12.71 0Z"
/>
<path
fill="currentColor"
d="M386.34 193.66L264.45 315.79A41.08 41.08 0 0 1 247.58 326l-25.9 8.67a35.92 35.92 0 0 1-44.33-44.33l8.67-25.9a41.08 41.08 0 0 1 10.19-16.87l122.13-121.91a8 8 0 0 0-5.65-13.66H104a56 56 0 0 0-56 56v240a56 56 0 0 0 56 56h240a56 56 0 0 0 56-56V199.31a8 8 0 0 0-13.66-5.65Z"
/>
</svg>
);
export const DeleteIcon = ({
size,
height = 12,
width = 10,
fill = "none",
...props
}: IconSvgProps) => (
<svg
height={size || height}
width={size || width}
viewBox="0 0 10 12"
fill={fill}
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M9.66683 0.666667H7.3335L6.66683 0H3.3335L2.66683 0.666667H0.333496V2H9.66683M1.00016 10.6667C1.00016 11.0203 1.14064 11.3594 1.39069 11.6095C1.64074 11.8595 1.97987 12 2.3335 12H7.66683C8.02045 12 8.35959 11.8595 8.60964 11.6095C8.85969 11.3594 9.00016 11.0203 9.00016 10.6667V2.66667H1.00016V10.6667Z"
fill="currentColor"
/>
</svg>
);
export const DotsYIcon = ({
size,
height = 24,
width = 24,
fill = "currentColor",
...props
}: IconSvgProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24">
<path
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M12 5.92A.96.96 0 1 0 12 4a.96.96 0 0 0 0 1.92m0 7.04a.96.96 0 1 0 0-1.92a.96.96 0 0 0 0 1.92M12 20a.96.96 0 1 0 0-1.92a.96.96 0 0 0 0 1.92">
</path>
</svg>
);
export const EyeIconMdi = ({
size,
height = 24,
width = 24,
fill = "currentColor",
...props
}: IconSvgProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
height={size || height}
width={size || width}
viewBox="0 0 24 24"
fill={fill}
{...props}
>
<path
fill="currentColor"
d="M12 9a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3m0 8a5 5 0 0 1-5-5a5 5 0 0 1 5-5a5 5 0 0 1 5 5a5 5 0 0 1-5 5m0-12.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5Z"
/>
</svg>
);
export const TimesIcon = ({
size,
height = 24,
width = 24,
fill = "currentColor",
...props
}: IconSvgProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
height={size || height}
width={size || width}
viewBox="0 0 24 24"
fill={fill}
{...props}
>
<path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" />
</svg>
);

View File

@ -0,0 +1,232 @@
"use client";
import {
TableCell,
TableRow,
Table,
TableHeader,
TableColumn,
TableBody,
Pagination,
Dropdown,
DropdownTrigger,
DropdownMenu,
DropdownItem,
Input,
User,
Card,
Divider,
Chip,
ChipProps,
} from "@nextui-org/react";
import { Button } from "@nextui-org/button";
import React, { Key, useCallback, useMemo, useState } from "react";
import {
AddIcon,
CreateIconIon,
DeleteIcon,
DotsYIcon,
EyeFilledIcon,
EyeIconMdi,
} from "@/components/icons";
import Link from "next/link";
type UserObject = {
id: number;
title: string;
status: string;
description: string;
avatar: string;
};
const statusColorMap = {
active: "success",
paused: "danger",
vacation: "warning",
};
export default function MagazineTable() {
type TableRow = (typeof magazineTable)[0];
const columns = [
{ name: "Title", uid: "title" },
{ name: "Description", uid: "description" },
{ name: "Action", uid: "actions" },
];
const magazineTable = [
{
id: 1,
title: "Proses pembuatan website humas ",
status: "active",
description: "Pembuatan website Humas adalah sebuah proses yang strategis untuk membangun identitas digital sebuah organisasi atau entitas, yang bertujuan untuk menyebarkan informasi kepada publik, memperkuat citra merek, serta menjaga keterbukaan dan transparansi. Proses ini melibatkan beberapa tahapan yang terstruktur dan terkoordinasi dengan baik",
avatar: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSa8Luglga9J2R3Bxt_PsWZISUHQWODD6_ZTAJ5mIQgxYCAE-YbkY81faTqp-hSA_jVPTs&usqp=CAU",
},
{
id: 2,
title: "Proses pembuatan website humas ",
status: "active",
description: "Pembuatan website Humas adalah sebuah proses yang strategis untuk membangun identitas digital sebuah organisasi atau entitas, yang bertujuan untuk menyebarkan informasi kepada publik, memperkuat citra merek, serta menjaga keterbukaan dan transparansi. Proses ini melibatkan beberapa tahapan yang terstruktur dan terkoordinasi dengan baik",
avatar: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSa8Luglga9J2R3Bxt_PsWZISUHQWODD6_ZTAJ5mIQgxYCAE-YbkY81faTqp-hSA_jVPTs&usqp=CAU",
},
{
id: 3,
title: "Proses pembuatan website humas ",
status: "active",
description: "Pembuatan website Humas adalah sebuah proses yang strategis untuk membangun identitas digital sebuah organisasi atau entitas, yang bertujuan untuk menyebarkan informasi kepada publik, memperkuat citra merek, serta menjaga keterbukaan dan transparansi. Proses ini melibatkan beberapa tahapan yang terstruktur dan terkoordinasi dengan baik",
avatar: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSa8Luglga9J2R3Bxt_PsWZISUHQWODD6_ZTAJ5mIQgxYCAE-YbkY81faTqp-hSA_jVPTs&usqp=CAU",
},
{
id: 4,
title: "Proses pembuatan website humas ",
status: "active",
description: "Pembuatan website Humas adalah sebuah proses yang strategis untuk membangun identitas digital sebuah organisasi atau entitas, yang bertujuan untuk menyebarkan informasi kepada publik, memperkuat citra merek, serta menjaga keterbukaan dan transparansi. Proses ini melibatkan beberapa tahapan yang terstruktur dan terkoordinasi dengan baik",
avatar: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSa8Luglga9J2R3Bxt_PsWZISUHQWODD6_ZTAJ5mIQgxYCAE-YbkY81faTqp-hSA_jVPTs&usqp=CAU",
},
{
id: 5,
title: "Proses pembuatan website humas ",
status: "active",
description: "Pembuatan website Humas adalah sebuah proses yang strategis untuk membangun identitas digital sebuah organisasi atau entitas, yang bertujuan untuk menyebarkan informasi kepada publik, memperkuat citra merek, serta menjaga keterbukaan dan transparansi. Proses ini melibatkan beberapa tahapan yang terstruktur dan terkoordinasi dengan baik",
avatar: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSa8Luglga9J2R3Bxt_PsWZISUHQWODD6_ZTAJ5mIQgxYCAE-YbkY81faTqp-hSA_jVPTs&usqp=CAU",
},
];
const renderCell = useCallback((magazine: TableRow, columnKey: Key) => {
const cellValue = magazine[columnKey as keyof UserObject];
const statusColorMap: Record<string, ChipProps["color"]> = {
active: "primary",
cancel: "danger",
pending: "success",
};
switch (columnKey) {
case "no":
return (
<div>{magazine.id}</div>
)
case "title":
return (
<div className="w-[350px]">{magazine.title}</div>
)
case "description":
return (
<div className="">{magazine.description}</div>
)
case "status":
return (
<Chip
className="capitalize "
color={statusColorMap[magazine.status]}
size="lg"
variant="flat"
>
<div className="flex flex-row items-center gap-2 justify-center">
{cellValue}
</div>
</Chip>
);
case "actions":
return (
<div className="relative flex justify-star items-center gap-2">
<Dropdown className="lg:min-w-[150px] bg-black text-white shadow border ">
<DropdownTrigger>
<Button isIconOnly size="lg" variant="light">
<DotsYIcon className="text-default-300" />
</Button>
</DropdownTrigger>
<DropdownMenu>
<DropdownItem
>
<Link
href={`/admin/magazine/detail`}
>
<EyeIconMdi className="inline mr-2 mb-1" />
Detail
</Link>
</DropdownItem>
<DropdownItem
>
<Link
href={`#`}
>
<CreateIconIon className="inline mr-2 mb-1" />
Edit
</Link>
</DropdownItem>
<DropdownItem
>
<Link
href={`#`}
>
<DeleteIcon
width={20}
height={16}
className="inline mr-2 mb-1"
/>
Delete
</Link>
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
);
default:
return cellValue;
}
}, []);
return (
<>
<div className="mx-3 my-5">
<Link href="/admin/magazine/create" >
<Button className="my-3 bg-blue-600 text-white" ><CreateIconIon />Create New Magazine</Button>
</Link>
<div className="flex flex-col items-center rounded-2xl">
<Table
// selectionMode="multiple"
aria-label="micro issue table"
className="rounded-xl"
classNames={{
th: "bg-white dark:bg-black text-black dark:text-white border-b-1 text-md",
base: "bg-white dark:bg-black border",
wrapper: "min-h-[50px] bg-transpararent text-black dark:text-white ",
}}
>
<TableHeader columns={columns}>
{(column) => (
<TableColumn key={column.uid}>{column.name}</TableColumn>
)}
</TableHeader>
<TableBody items={magazineTable} emptyContent={"No data to display."}>
{(item) => (
<TableRow key={item.id}>
{(columnKey) => (
<TableCell>{renderCell(item, columnKey)}</TableCell>
)}
</TableRow>
)}
</TableBody>
</Table>
</div>
</div>
</>
);
}

95
config/swal.ts Normal file
View File

@ -0,0 +1,95 @@
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { useRouter } from "next/navigation";
const MySwal = withReactContent(Swal);
const Toast = MySwal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener("mouseenter", Swal.stopTimer);
toast.addEventListener("mouseleave", Swal.resumeTimer);
},
});
export function loading(msg?: any) {
let timerInterval: any;
MySwal.fire({
title: msg || "Loading...",
allowOutsideClick: false,
timerProgressBar: true,
didOpen: () => {
MySwal.showLoading();
timerInterval = setInterval(() => {}, 100);
},
willClose: () => {
clearInterval(timerInterval);
},
});
}
export function error(msg?: any) {
MySwal.fire({
icon: "error",
title: "Failed...",
text: msg || "Unknown Error",
});
}
export function successRouter(redirect: string, router?: any) {
MySwal.fire({
title: "Success!",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "Ok",
allowOutsideClick: false,
}).then((result) => {
if (result.isConfirmed) {
router.push(redirect);
}
});
}
export function success(title: string) {
MySwal.fire({
title: title || "Success!",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
return true;
}
});
}
export function close() {
MySwal.close();
}
export function warning(text: string, redirect: string, router?: any) {
MySwal.fire({
title: text,
icon: "warning",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
router.push(redirect);
}
});
}
export function successToast(title: string, text: string) {
Toast.fire({
icon: "success",
title: title,
text: text,
});
}

302
package-lock.json generated
View File

@ -33,6 +33,7 @@
"eslint-config-next": "14.0.2",
"framer-motion": "^10.18.0",
"intl-messageformat": "^10.5.0",
"jodit-react": "^4.0.25",
"next": "14.0.2",
"next-themes": "^0.2.1",
"postcss": "8.4.31",
@ -43,11 +44,12 @@
"react-icons": "^5.0.1",
"react-tailwindcss-datepicker": "^1.6.6",
"react-tweet": "^3.2.0",
"sweetalert2-react-content": "^5.0.7",
"swiper": "^11.0.6",
"tailwind-variants": "^0.1.18",
"tailwindcss": "3.3.5",
"typescript": "5.0.4",
"zod": "^3.22.4"
"zod": "^1.11.17"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -338,6 +340,126 @@
"glob": "7.1.7"
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.2.tgz",
"integrity": "sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.2.tgz",
"integrity": "sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.2.tgz",
"integrity": "sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.2.tgz",
"integrity": "sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.2.tgz",
"integrity": "sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.2.tgz",
"integrity": "sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.2.tgz",
"integrity": "sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.2.tgz",
"integrity": "sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "14.0.2",
"cpu": [
@ -2849,6 +2971,15 @@
"has-symbols": "^1.0.3"
}
},
"node_modules/autobind-decorator": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/autobind-decorator/-/autobind-decorator-2.4.0.tgz",
"integrity": "sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw==",
"engines": {
"node": ">=8.10",
"npm": ">=6.4.1"
}
},
"node_modules/autoprefixer": {
"version": "10.4.16",
"funding": [
@ -4525,6 +4656,26 @@
"jiti": "bin/jiti.js"
}
},
"node_modules/jodit": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/jodit/-/jodit-4.1.16.tgz",
"integrity": "sha512-rqBGuYkmaU4cJrmid2vtdBFMA0eCFp6S7qhP2aNf92wBiLYmo+UnvyW08lH+CcZ2ZoWtVjEiqzGMvj8kZ0zsKA==",
"dependencies": {
"autobind-decorator": "^2.4.0"
}
},
"node_modules/jodit-react": {
"version": "4.0.25",
"resolved": "https://registry.npmjs.org/jodit-react/-/jodit-react-4.0.25.tgz",
"integrity": "sha512-HFbbpabQlE3UdD5mOVm/ZHCRVMtNHCy5oZi4mWquM1W6uNrQG5sO7GuIYTxmW84qfTpuKPWjyw2q1ov/YFW8ug==",
"dependencies": {
"jodit": "^4.1.16"
},
"peerDependencies": {
"react": "~0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "~0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"license": "MIT"
@ -5830,6 +5981,26 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/sweetalert2": {
"version": "11.10.7",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.7.tgz",
"integrity": "sha512-5Jlzrmaitay6KzU+2+LhYu9q+L4v/dZ8oZyEDH14ep0C/QilCnFLHmqAyD/Lhq/lm5DiwsOs6Tr58iv8k3wyGg==",
"peer": true,
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/limonte"
}
},
"node_modules/sweetalert2-react-content": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/sweetalert2-react-content/-/sweetalert2-react-content-5.0.7.tgz",
"integrity": "sha512-8Fk82Mpk45lFXpJWKIFF/lq8k/dJKDDQGFcuqVosaL/qRdViyAs5+u37LoTGfnOIvf+rfQB3PAXcp1XLLn+0ew==",
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0",
"sweetalert2": "^11.0.0"
}
},
"node_modules/swiper": {
"version": "11.0.7",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.0.7.tgz",
@ -6327,132 +6498,9 @@
}
},
"node_modules/zod": {
"version": "3.22.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.2.tgz",
"integrity": "sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.2.tgz",
"integrity": "sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.2.tgz",
"integrity": "sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.2.tgz",
"integrity": "sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.2.tgz",
"integrity": "sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.2.tgz",
"integrity": "sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.2.tgz",
"integrity": "sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.2.tgz",
"integrity": "sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
"version": "1.11.17",
"resolved": "https://registry.npmjs.org/zod/-/zod-1.11.17.tgz",
"integrity": "sha512-UzIwO92D0dSFwIRyyqAfRXICITLjF0IP8tRbEK/un7adirMssWZx8xF/1hZNE7t61knWZ+lhEuUvxlu2MO8qqA=="
}
}
}

View File

@ -34,6 +34,7 @@
"eslint-config-next": "14.0.2",
"framer-motion": "^10.18.0",
"intl-messageformat": "^10.5.0",
"jodit-react": "^4.0.25",
"next": "14.0.2",
"next-themes": "^0.2.1",
"postcss": "8.4.31",
@ -44,10 +45,11 @@
"react-icons": "^5.0.1",
"react-tailwindcss-datepicker": "^1.6.6",
"react-tweet": "^3.2.0",
"sweetalert2-react-content": "^5.0.7",
"swiper": "^11.0.6",
"tailwind-variants": "^0.1.18",
"tailwindcss": "3.3.5",
"typescript": "5.0.4",
"zod": "^3.22.4"
"zod": "^1.11.17"
}
}