diff --git a/package.json b/package.json
index 2ffb000..14ae99a 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@faker-js/faker": "^8.4.1",
"@fontsource/inter": "^5.0.16",
"@fontsource/plus-jakarta-sans": "^5.0.18",
+ "@fullcalendar/react": "^6.1.11",
"@mui/icons-material": "^5.15.0",
"@mui/material": "^5.15.0",
"@mui/material-nextjs": "^5.15.0",
@@ -22,6 +23,7 @@
"@mui/x-date-pickers": "^6.18.7",
"@unly/universal-language-detector": "^2.0.3",
"apexcharts": "^3.45.2",
+ "date-holidays": "^3.23.11",
"dayjs": "^1.11.10",
"fullcalendar": "^6.1.11",
"i18next": "^23.7.11",
diff --git a/src/app/(main)/settings/holiday/page.tsx b/src/app/(main)/settings/holiday/page.tsx
new file mode 100644
index 0000000..16a5ac2
--- /dev/null
+++ b/src/app/(main)/settings/holiday/page.tsx
@@ -0,0 +1,48 @@
+import CompanyHoliday from "@/components/CompanyHoliday";
+import { Metadata } from "next";
+import { getServerI18n } from "@/i18n";
+import Add from "@mui/icons-material/Add";
+import Button from "@mui/material/Button";
+import Stack from "@mui/material/Stack";
+import Typography from "@mui/material/Typography";
+import Link from "next/link";
+import { Suspense } from "react";
+import { fetchCompanys, preloadCompanys } from "@/app/api/companys";
+
+export const metadata: Metadata = {
+ title: "Holiday",
+};
+
+const Company: React.FC = async () => {
+ const { t } = await getServerI18n("holiday");
+
+ // Preload necessary dependencies
+
+ return (
+ <>
+
+
+ {t("Company Holiday")}
+
+ {/* }
+ LinkComponent={Link}
+ href="/settings/holiday/create"
+ >
+ {t("Create Holiday")}
+ */}
+
+ }>
+
+
+ >
+ )
+};
+
+export default Company;
diff --git a/src/app/api/holidays/index.ts b/src/app/api/holidays/index.ts
new file mode 100644
index 0000000..0a90ffc
--- /dev/null
+++ b/src/app/api/holidays/index.ts
@@ -0,0 +1,23 @@
+import { serverFetchJson } from "@/app/utils/fetchUtil";
+import { BASE_API_URL } from "@/config/api";
+import { cache } from "react";
+import "server-only";
+import EventInput from '@fullcalendar/react';
+
+export interface HolidaysResult extends EventInput {
+ title: string;
+ date: string;
+ extendedProps: {
+ calendar: string;
+ };
+}
+
+export const preloadCompanys = () => {
+ fetchHolidays();
+};
+
+export const fetchHolidays = cache(async () => {
+ return serverFetchJson(`${BASE_API_URL}/companys`, {
+ next: { tags: ["companys"] },
+ });
+});
\ No newline at end of file
diff --git a/src/components/CompanyHoliday/CompanyHoliday.tsx b/src/components/CompanyHoliday/CompanyHoliday.tsx
new file mode 100644
index 0000000..bfa5ecb
--- /dev/null
+++ b/src/components/CompanyHoliday/CompanyHoliday.tsx
@@ -0,0 +1,166 @@
+"use client";
+
+import { HolidaysResult } from "@/app/api/holidays";
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Grid, Stack } from '@mui/material/';
+import { useTranslation } from "react-i18next";
+import FullCalendar from '@fullcalendar/react'
+import dayGridPlugin from '@fullcalendar/daygrid' // a plugin!
+import interactionPlugin from "@fullcalendar/interaction" // needed for dayClick
+import Holidays from "date-holidays";
+import CompanyHolidayDialog from "./CompanyHolidayDialog";
+import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form";
+import { EventBusy } from "@mui/icons-material";
+interface Props {
+ holidays: HolidaysResult[];
+}
+
+const CompanyHoliday: React.FC = ({ holidays }) => {
+ const { t } = useTranslation("holidays");
+
+ const hd = new Holidays('HK')
+ console.log(holidays)
+
+ const [companyHolidays, setCompanyHolidays] = useState([])
+ const [dateContent, setDateContent] = useState<{ date: string }>({date: ''})
+ const [open, setOpen] = useState(false);
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const getPublicHolidaysList = () => {
+ const currentYear = new Date().getFullYear()
+ const currentYearHolidays = hd.getHolidays(currentYear)
+ const nextYearHolidays = hd.getHolidays(currentYear + 1)
+ const events_cyhd = currentYearHolidays.map(ele => {
+ const tempDay = new Date(ele.date)
+ const tempYear = tempDay.getFullYear()
+ const tempMonth = tempDay.getMonth() + 1 < 10 ? `0${ tempDay.getMonth() + 1}` : tempDay.getMonth() + 1
+ const tempDate = tempDay.getDate() < 10 ? `0${tempDay.getDate()}` : tempDay.getDate()
+ let tempName = ""
+ switch (ele.name) {
+ case "复活节":
+ tempName = "復活節"
+ break
+ case "劳动节":
+ tempName = "勞動節"
+ break
+ case "端午节":
+ tempName = "端午節"
+ break
+ case "重阳节":
+ tempName = "重陽節"
+ break
+ case "圣诞节后的第一个工作日":
+ tempName = "聖誕節後的第一个工作日"
+ break
+ default:
+ tempName = ele.name
+ break
+ }
+
+ return {date: `${tempYear}-${tempMonth}-${tempDate}`, title: tempName, extendedProps: {calendar: 'holiday'}}
+ })
+
+ const events_nyhd = nextYearHolidays.map(ele => {
+ const tempDay = new Date(ele.date)
+ const tempYear = tempDay.getFullYear()
+ const tempMonth = tempDay.getMonth() + 1 < 10 ? `0${ tempDay.getMonth() + 1}` : tempDay.getMonth() + 1
+ const tempDate = tempDay.getDate() < 10 ? `0${tempDay.getDate()}` : tempDay.getDate()
+ let tempName = ""
+ switch (ele.name) {
+ case "复活节":
+ tempName = "復活節"
+ break
+ case "劳动节":
+ tempName = "勞動節"
+ break
+ case "端午节":
+ tempName = "端午節"
+ break
+ case "重阳节":
+ tempName = "重陽節"
+ break
+ case "圣诞节后的第一个工作日":
+ tempName = "聖誕節後的第一个工作日"
+ break
+ default:
+ tempName = ele.name
+ break
+ }
+ return {date: `${tempYear}-${tempMonth}-${tempDate}`, title: tempName, extendedProps: {calendar: 'holiday'}}
+ })
+
+ setCompanyHolidays([...events_cyhd, ...events_nyhd] as HolidaysResult[])
+ }
+
+ useEffect(()=>{
+ getPublicHolidaysList()
+ },[])
+
+ const handleDateClick = (event:any) => {
+ console.log(event.dateStr)
+ setDateContent({date: event.dateStr})
+ setOpen(true);
+ }
+
+ const handleEventClick = (event:any) => {
+ console.log(event)
+ }
+
+ const onSubmit = useCallback>(
+ async (data) => {
+ try {
+ console.log(data);
+ // console.log(JSON.stringify(data));
+ } catch (e) {
+ console.log(e);
+ }
+ },
+ [t, ],
+ );
+
+ const onSubmitError = useCallback>(
+ (errors) => {
+ console.log(errors)
+ },
+ [],
+ );
+
+
+ const formProps = useForm({
+ defaultValues: {
+ title: ""
+ },
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+ }
+ />
+
+ >
+ );
+};
+
+export default CompanyHoliday;
diff --git a/src/components/CompanyHoliday/CompanyHolidayDialog.tsx b/src/components/CompanyHoliday/CompanyHolidayDialog.tsx
new file mode 100644
index 0000000..3b9419f
--- /dev/null
+++ b/src/components/CompanyHoliday/CompanyHolidayDialog.tsx
@@ -0,0 +1,79 @@
+import React, { useState } from 'react';
+import { Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Grid, FormControl } from '@mui/material/';
+import { useForm, useFormContext } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers';
+import dayjs from 'dayjs';
+import { INPUT_DATE_FORMAT } from '@/app/utils/formatUtil';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+
+interface CompanyHolidayDialogProps {
+ open: boolean;
+ onClose: () => void;
+ title: string;
+ actions: React.ReactNode;
+ content: Content
+}
+
+interface Content {
+ date: string
+}
+
+const CompanyHolidayDialog: React.FC = ({ open, onClose, title, actions, content }) => {
+ const {
+ t,
+ i18n: { language },
+ } = useTranslation();
+
+ const {
+ register,
+ formState: { errors },
+ setValue,
+ getValues,
+ } = useFormContext();
+
+ return (
+
+
+
+ );
+};
+
+export default CompanyHolidayDialog;
\ No newline at end of file
diff --git a/src/components/CompanyHoliday/CompanyHolidayLoading.tsx b/src/components/CompanyHoliday/CompanyHolidayLoading.tsx
new file mode 100644
index 0000000..5b8c02d
--- /dev/null
+++ b/src/components/CompanyHoliday/CompanyHolidayLoading.tsx
@@ -0,0 +1,40 @@
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import Skeleton from "@mui/material/Skeleton";
+import Stack from "@mui/material/Stack";
+import React from "react";
+
+// Can make this nicer
+export const CompanyHolidayLoading: React.FC = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default CompanyHolidayLoading;
diff --git a/src/components/CompanyHoliday/CompanyHolidayWrapper.tsx b/src/components/CompanyHoliday/CompanyHolidayWrapper.tsx
new file mode 100644
index 0000000..0c21148
--- /dev/null
+++ b/src/components/CompanyHoliday/CompanyHolidayWrapper.tsx
@@ -0,0 +1,24 @@
+// import { fetchCompanyCategories, fetchCompanys } from "@/app/api/companys";
+import React, { useState, } from "react";
+import CompanyHoliday from "./CompanyHoliday";
+import CompanyHolidayLoading from "./CompanyHolidayLoading";
+import { fetchCompanys } from "@/app/api/companys";
+import Holidays from "date-holidays";
+import { HolidaysResult, fetchHolidays } from "@/app/api/holidays";
+
+interface SubComponents {
+ Loading: typeof CompanyHolidayLoading;
+}
+
+const CompanyHolidayWrapper: React.FC & SubComponents = async () => {
+ // const Companys = await fetchCompanys();
+
+ const companyHolidays: HolidaysResult[] = await fetchHolidays()
+
+
+ return ;
+};
+
+CompanyHolidayWrapper.Loading = CompanyHolidayLoading;
+
+export default CompanyHolidayWrapper;
diff --git a/src/components/CompanyHoliday/index.ts b/src/components/CompanyHoliday/index.ts
new file mode 100644
index 0000000..3dddafc
--- /dev/null
+++ b/src/components/CompanyHoliday/index.ts
@@ -0,0 +1 @@
+export { default } from "./CompanyHolidayWrapper";