Skip to content

Commit

Permalink
Holiday calendar added (#1810)
Browse files Browse the repository at this point in the history
* calendar component added on leave management

* month view width fixed on mobile screens

* holiday list updated from timeoffHolidays to admin created holidays

---------

Co-authored-by: Shruti Apte <shruti@saeloun.com>
Co-authored-by: Apoorv Tiwari <tiwari.apoorv1316@gmail.com>
  • Loading branch information
3 people authored Apr 29, 2024
1 parent ab40c90 commit 816c9cc
Show file tree
Hide file tree
Showing 11 changed files with 304 additions and 139 deletions.
5 changes: 2 additions & 3 deletions app/javascript/src/common/CustomYearPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ type customYearPickerProps = {

const defaultWrapperClassName = "flex items-center justify-center";

const defaultYearClassName =
"outline-none appearance-none bg-transparent text-white";
const defaultYearClassName = "outline-none appearance-none bg-transparent";

const CustomYearPicker = ({
wrapperClassName,
Expand Down Expand Up @@ -64,7 +63,7 @@ const CustomYearPicker = ({
>
{years.map((year, index) => (
<option
className="text-base font-medium text-white"
className="text-base font-medium"
key={`year${index}`}
value={year}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const CalendarComponent = ({
}) => (
<div
key={id}
className={`flex flex-col items-center justify-start bg-miru-gray-100 py-3 ${
className={`flex w-full flex-col items-center justify-start bg-miru-gray-100 py-3 lg:w-1/3 ${
isWiderScreen ? "px-3" : "px-2"
}`}
>
Expand Down
100 changes: 100 additions & 0 deletions app/javascript/src/common/HolidayModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from "react";

import { XIcon } from "miruIcons";
import { Button, Modal } from "StyledComponents";

import CustomYearPicker from "common/CustomYearPicker";
import { MobileEditHeader } from "common/Mobile/MobileEditHeader";
import { yearCalendar } from "constants/leaveType";
import { useUserContext } from "context/UserContext";

import CalendarComponent from "./CalendarComponent";

const HolidayModal = ({
tileContent,
toggleCalendarModal,
showCalendar,
currentYear,
setCurrentYear,
}) => {
const { isDesktop } = useUserContext();

const CalendarForm = () => (
<div className="modal__form flex-col bg-white lg:px-4">
<div className="mt-3 flex w-full items-center justify-between lg:justify-end">
<div className="flex flex-row items-center">
<div className="mr-4 flex flex-row items-center text-xs font-medium lg:text-sm">
<div className="mr-2 h-4 w-4 rounded-2xl bg-miru-chart-pink-600" />
Holidays
</div>
<div className="flex flex-row items-center text-xs font-medium lg:text-sm">
<div className="mr-2 h-4 w-4 rounded-2xl bg-miru-gray-800" />
Optional Holidays
</div>
</div>
<CustomYearPicker
currentYear={currentYear}
setCurrentYear={setCurrentYear}
wrapperClassName="text-miru-han-purple-1000 flex items-center justify-end lg:hidden text-sm"
/>
</div>
{Object.keys(yearCalendar).map((quarters, key) => (
<div className="flex flex-col gap-4 pt-4 lg:flex-row" key={key}>
{yearCalendar[quarters].quarter.map((month, key) => (
<CalendarComponent
id={month.id}
key={key}
name={month.name}
tileContent={tileContent}
year={currentYear}
/>
))}
</div>
))}
</div>
);

if (isDesktop) {
return (
<Modal
customStyle="min-w-60v lg:p-0 lg:pb-6 hidden lg:block"
isOpen={showCalendar}
onClose={toggleCalendarModal}
>
<div className="modal__position mx-0 h-10 w-full items-center bg-miru-han-purple-1000 px-4 text-white">
<span className="flex-1 pl-4 text-base">
Public and optional holidays
</span>
<CustomYearPicker
currentYear={currentYear}
setCurrentYear={setCurrentYear}
/>
<div className="modal__close flex-1 text-right">
<Button className="modal__button" onClick={toggleCalendarModal}>
<XIcon color="#CDD6DF" size={15} />
</Button>
</div>
</div>
<CalendarForm />
</Modal>
);
}

if (showCalendar) {
return (
<div className="absolute inset-0 z-50 bg-white">
<MobileEditHeader
backHref="/leave-management/"
href=""
showEdit={false}
title="Public & Optional Holidays"
/>
<div className="my-12">
<CalendarForm />
</div>
</div>
);
}
};

export default HolidayModal;
9 changes: 6 additions & 3 deletions app/javascript/src/common/Mobile/MobileEditHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ export const MobileEditHeader = ({
title = "",
backHref,
href,
showEdit = true,
}) => (
<div className={wrapperClassName}>
<div className="flex flex-row items-center">
<BackButton href={backHref} />
<span>{title}</span>
</div>
<div className="items-center pr-4 font-bold text-miru-han-purple-1000">
<Link to={href}>Edit</Link>
</div>
{showEdit && (
<div className="items-center pr-4 font-bold text-miru-han-purple-1000">
<Link to={href}>Edit</Link>
</div>
)}
</div>
);
160 changes: 116 additions & 44 deletions app/javascript/src/components/LeaveManagement/Container/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React from "react";
import React, { Fragment, useState } from "react";

import { minToHHMM } from "helpers";
import { XIcon } from "miruIcons";
import { getYear } from "date-fns";
import dayjs from "dayjs";
import { minToHHMM, companyDateFormater } from "helpers";
import { XIcon, CalendarIcon } from "miruIcons";
import { Button, Tooltip } from "StyledComponents";

import { Divider } from "common/Divider";
import HolidayModal from "common/HolidayModal";
import { useUserContext } from "context/UserContext";

import LeaveBlock from "./LeaveBlock";
import Table from "./Table";
Expand All @@ -15,51 +20,118 @@ const Container = ({
totalTimeoffEntriesDuration,
selectedLeaveType,
setSelectedLeaveType,
}) => (
<div className="mx-4 my-6 h-full lg:mx-0">
<p className="text-base font-normal text-miru-dark-purple-1000 lg:text-2xl">
{getLeaveBalanaceDateText()}
</p>
<div className="mt-6 grid w-full gap-4 lg:grid-cols-3">
{leaveBalance.map((leaveType, index) => (
<LeaveBlock
key={index}
leaveType={leaveType}
selectedLeaveType={selectedLeaveType}
setSelectedLeaveType={setSelectedLeaveType}
/>
))}
optionalHolidayList,
nationalHolidayList,
}) => {
const [showCalendar, setShowCalendar] = useState<boolean>(false);
const [currentYear, setCurrentYear] = useState<number>(getYear(new Date()));
const { company } = useUserContext();
const dateFormat = companyDateFormater(company?.date_format);
const toggleCalendarModal = () => setShowCalendar(!showCalendar);

const HolidayButton = ({ content, date, className }) => (
<div className={`holiday-wrapper ${className}`}>
<Tooltip className="tooltip" content={content.name}>
<span>{date.getDate()}</span>
</Tooltip>
</div>
<div className="mt-10">
<div className="flex items-center justify-between py-3 lg:py-5">
<div className="flex items-center">
<span className="mr-4 text-lg font-bold text-miru-dark-purple-1000 lg:text-xl">
Leave Details
</span>
{selectedLeaveType && (
<div className="flex items-center justify-center rounded-xl bg-miru-gray-400 px-3 py-1 lg:mx-2 lg:my-0">
<span className="tracking-wide text-base font-normal capitalize text-miru-dark-purple-1000">
{selectedLeaveType.name}
);

const tileContent = ({ date }) => {
const currentDate = dayjs(date).format(dateFormat);
const isHoliday = nationalHolidayList?.find(
holiday => holiday.date === currentDate
);

const isOptionalHoliday = optionalHolidayList?.find(
holiday => holiday.date === currentDate
);

if (isHoliday || isOptionalHoliday) {
return (
<HolidayButton
className={isHoliday ? "holiday" : "optional-holiday"}
content={isHoliday || isOptionalHoliday}
date={date}
/>
);
}

return <button>{date.getDate()}</button>;
};

return (
<Fragment>
<div className="mx-4 my-6 h-full lg:mx-0">
<div className="flex w-full items-center justify-between">
<p className="text-base font-normal text-miru-dark-purple-1000 lg:text-2xl">
{getLeaveBalanaceDateText()}
</p>
<Button
className="flex items-center text-center text-xs font-bold lg:px-4"
style="secondary"
onClick={toggleCalendarModal}
>
<CalendarIcon
className="mr-2 text-miru-han-purple-1000 lg:hidden"
size={16}
weight="bold"
/>
<span className="lg:hidden">Holiday</span>
<span className="hidden lg:block">View Holiday Calendar</span>
</Button>
</div>
<div className="mt-6 grid w-full gap-4 lg:grid-cols-3">
{leaveBalance.map((leaveType, index) => (
<LeaveBlock
key={index}
leaveType={leaveType}
selectedLeaveType={selectedLeaveType}
setSelectedLeaveType={setSelectedLeaveType}
/>
))}
</div>
<div className="mt-10">
<div className="flex items-center justify-between py-3 lg:py-5">
<div className="flex items-center">
<span className="mr-4 text-lg font-bold text-miru-dark-purple-1000 lg:text-xl">
Leave Details
</span>
<XIcon
className="ml-2 cursor-pointer"
size={14}
onClick={() => setSelectedLeaveType(null)}
/>
{selectedLeaveType && (
<div className="flex items-center justify-center rounded-xl bg-miru-gray-400 px-3 py-1 lg:mx-2 lg:my-0">
<span className="tracking-wide text-base font-normal capitalize text-miru-dark-purple-1000">
{selectedLeaveType.name}
</span>
<XIcon
className="ml-2 cursor-pointer"
size={14}
onClick={() => setSelectedLeaveType(null)}
/>
</div>
)}
</div>
)}
<p className="text-sm font-medium text-miru-dark-purple-1000 lg:text-base">
Total :
<span className="font-bold">
{minToHHMM(totalTimeoffEntriesDuration)}
</span>
</p>
</div>
<Divider />
<Table timeoffEntries={timeoffEntries} />
</div>
<p className="text-sm font-medium text-miru-dark-purple-1000 lg:text-base">
Total :{" "}
<span className="font-bold">
{minToHHMM(totalTimeoffEntriesDuration)}
</span>
</p>
</div>
<Divider />
<Table timeoffEntries={timeoffEntries} />
</div>
</div>
);
{showCalendar && (
<HolidayModal
currentYear={currentYear}
setCurrentYear={setCurrentYear}
showCalendar={showCalendar}
tileContent={tileContent}
toggleCalendarModal={toggleCalendarModal}
/>
)}
</Fragment>
);
};

export default Container;
20 changes: 20 additions & 0 deletions app/javascript/src/components/LeaveManagement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";

import { getYear, format } from "date-fns";

import holidaysApi from "apis/holidays";
import timeoffEntryApi from "apis/timeoffEntry";
import Loader from "common/Loader/index";
import withLayout from "common/Mobile/HOC/withLayout";
Expand All @@ -27,6 +28,23 @@ const LeaveManagement = () => {
useState(0);
const [optionalTimeoffEntries, setOptionalTimeoffEntries] = useState([]);
const [nationalTimeoffEntries, setNationalTimeoffEntries] = useState([]);
const [optionalHolidayList, setOptionalHolidayList] = useState<Array<any>>(
[]
);

const [nationalHolidayList, setNationalHolidayList] = useState<Array<any>>(
[]
);

const fetchHolidayData = async () => {
const res = await holidaysApi.allHolidays();
setOptionalHolidayList(res.data.holidays[0].optional_holidays);
setNationalHolidayList(res.data.holidays[0].national_holidays);
};

useEffect(() => {
fetchHolidayData();
}, []);

useEffect(() => {
fetchTimeoffEntries();
Expand Down Expand Up @@ -130,6 +148,8 @@ const LeaveManagement = () => {
<Container
getLeaveBalanaceDateText={getLeaveBalanaceDateText}
leaveBalance={leaveBalance}
nationalHolidayList={nationalHolidayList}
optionalHolidayList={optionalHolidayList}
selectedLeaveType={selectedLeaveType}
setSelectedLeaveType={setSelectedLeaveType}
timeoffEntries={filterTimeoffEntries}
Expand Down
Loading

0 comments on commit 816c9cc

Please sign in to comment.