diff --git a/docs/reference/endpoint-inventory.json b/docs/reference/endpoint-inventory.json index 526b5c137..136101112 100644 --- a/docs/reference/endpoint-inventory.json +++ b/docs/reference/endpoint-inventory.json @@ -1308,6 +1308,27 @@ "variables": [ "companyId" ] + }, + "UNSTABLE_TimeOff.PolicyList": { + "endpoints": [ + { + "method": "GET", + "path": "/v1/companies/:companyUuid/time_off_policies" + }, + { + "method": "PUT", + "path": "/v1/time_off_policies/:timeOffPolicyUuid/deactivate" + }, + { + "method": "GET", + "path": "/v1/companies/:companyId/employees" + } + ], + "variables": [ + "companyId", + "companyUuid", + "timeOffPolicyUuid" + ] } }, "flows": { @@ -2088,8 +2109,25 @@ "UNSTABLE_TimeOff.ViewPolicyDetails", "UNSTABLE_TimeOff.ViewPolicyEmployees" ], - "endpoints": [], - "variables": [] + "endpoints": [ + { + "method": "GET", + "path": "/v1/companies/:companyUuid/time_off_policies" + }, + { + "method": "PUT", + "path": "/v1/time_off_policies/:timeOffPolicyUuid/deactivate" + }, + { + "method": "GET", + "path": "/v1/companies/:companyId/employees" + } + ], + "variables": [ + "companyId", + "companyUuid", + "timeOffPolicyUuid" + ] } } } diff --git a/docs/reference/endpoint-reference.md b/docs/reference/endpoint-reference.md index d6ac3a31a..26fed3b16 100644 --- a/docs/reference/endpoint-reference.md +++ b/docs/reference/endpoint-reference.md @@ -244,6 +244,14 @@ import inventory from '@gusto/embedded-react-sdk/endpoint-inventory.json' | **Payroll.TransitionCreation** | POST | `/v1/companies/:companyId/payrolls` | | | GET | `/v1/companies/:companyId/pay_schedules` | +## UNSTABLE_TimeOff components + +| Component | Method | Path | +| --- | --- | --- | +| **UNSTABLE_TimeOff.PolicyList** | GET | `/v1/companies/:companyUuid/time_off_policies` | +| | PUT | `/v1/time_off_policies/:timeOffPolicyUuid/deactivate` | +| | GET | `/v1/companies/:companyId/employees` | + ## Flows Flows compose multiple blocks into a single workflow. The endpoint list for a flow is the union of all its block endpoints. diff --git a/src/components/UNSTABLE_TimeOff/PolicyList/PolicyList.tsx b/src/components/UNSTABLE_TimeOff/PolicyList/PolicyList.tsx index ce468323e..88883f394 100644 --- a/src/components/UNSTABLE_TimeOff/PolicyList/PolicyList.tsx +++ b/src/components/UNSTABLE_TimeOff/PolicyList/PolicyList.tsx @@ -1,43 +1,120 @@ +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useQueryClient } from '@tanstack/react-query' +import { + useTimeOffPoliciesGetAllSuspense, + invalidateAllTimeOffPoliciesGetAll, +} from '@gusto/embedded-api/react-query/timeOffPoliciesGetAll' +import { useTimeOffPoliciesDeactivateMutation } from '@gusto/embedded-api/react-query/timeOffPoliciesDeactivate' +import { useEmployeesListSuspense } from '@gusto/embedded-api/react-query/employeesList' +import type { TimeOffPolicy } from '@gusto/embedded-api/models/components/timeoffpolicy' +import { PolicyListPresentation } from './PolicyListPresentation' +import type { PolicyListItem } from './PolicyListTypes' import { BaseComponent, type BaseComponentInterface } from '@/components/Base' +import { useBase } from '@/components/Base/useBase' import { componentEvents } from '@/shared/constants' +import { useI18n } from '@/i18n' -export interface PolicyListProps extends BaseComponentInterface { +export interface PolicyListProps extends BaseComponentInterface<'Company.TimeOff.TimeOffPolicies'> { companyId: string } export function PolicyList(props: PolicyListProps) { return ( -
-

Policy List (companyId: {props.companyId})

- - - -
+
) } + +function Root({ companyId }: PolicyListProps) { + useI18n('Company.TimeOff.TimeOffPolicies') + const { t } = useTranslation('Company.TimeOff.TimeOffPolicies') + const { onEvent, baseSubmitHandler } = useBase() + const queryClient = useQueryClient() + + const [deleteSuccessAlert, setDeleteSuccessAlert] = useState(null) + const [isDeletingPolicyId, setIsDeletingPolicyId] = useState(null) + + const { data: policiesData } = useTimeOffPoliciesGetAllSuspense({ + companyUuid: companyId, + }) + const timeOffPolicies = policiesData.timeOffPolicies ?? [] + + const { data: employeesData } = useEmployeesListSuspense({ + companyId, + terminated: false, + }) + const totalActiveEmployees = employeesData.showEmployees?.length ?? 0 + + const { mutateAsync: deactivatePolicy } = useTimeOffPoliciesDeactivateMutation() + + const policies: PolicyListItem[] = timeOffPolicies.map((policy: TimeOffPolicy) => { + const enrolledCount = policy.employees.length + let enrolledDisplay: string + + if (enrolledCount > 0 && enrolledCount === totalActiveEmployees) { + enrolledDisplay = t('allEmployeesLabel') + } else if (enrolledCount > 0) { + enrolledDisplay = t('employeeCount', { count: enrolledCount }) + } else { + enrolledDisplay = t('enrolledDash') + } + + return { + uuid: policy.uuid, + name: policy.name, + policyType: policy.policyType, + isComplete: policy.complete ?? false, + enrolledDisplay, + } + }) + + const handleCreatePolicy = () => { + onEvent(componentEvents.TIME_OFF_CREATE_POLICY) + } + + const handleEditPolicy = (policy: PolicyListItem) => { + onEvent(componentEvents.TIME_OFF_VIEW_POLICY, { + policyId: policy.uuid, + policyType: policy.policyType, + }) + } + + const handleFinishSetup = (policy: PolicyListItem) => { + onEvent(componentEvents.TIME_OFF_VIEW_POLICY, { + policyId: policy.uuid, + policyType: policy.policyType, + }) + } + + const handleDeletePolicy = async (policy: PolicyListItem) => { + setIsDeletingPolicyId(policy.uuid) + await baseSubmitHandler({}, async () => { + await deactivatePolicy({ + request: { + timeOffPolicyUuid: policy.uuid, + }, + }) + + await invalidateAllTimeOffPoliciesGetAll(queryClient) + setDeleteSuccessAlert(t('flash.policyDeleted', { name: policy.name })) + }) + setIsDeletingPolicyId(null) + } + + return ( + { + setDeleteSuccessAlert(null) + }} + isDeletingPolicyId={isDeletingPolicyId} + /> + ) +}