Skip to content

Commit

Permalink
[Feature]: Confirm Status Change With Time Sheet (#2916)
Browse files Browse the repository at this point in the history
* feat:Implemented the ConfirmStatusChange modal to handle status transitions

* feat:Implemented the ConfirmStatusChange modal to handle status transitions

* fix: error
  • Loading branch information
Innocent-Akim authored Aug 19, 2024
1 parent 6b582e8 commit 7ffcd36
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 109 deletions.
4 changes: 2 additions & 2 deletions apps/web/lib/components/time-picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function TimePicker({ onChange, defaultValue }: IPopoverTimePicker) {
<Button
variant={"outline"}
className={cn(
"w-full justify-start text-left font-normal dark:bg-dark--theme-light text-[14px]",
"w-full justify-start text-left font-normal dark:bg-dark--theme-light text-[14px] dark:border-slate-700",
!time.minute && "text-muted-foreground"
)}
>
Expand Down Expand Up @@ -167,7 +167,7 @@ interface TimerPickerButtonProps {
// eslint-disable-next-line react/display-name
const TimerPickerButton: React.FC<TimerPickerButtonProps> = React.memo(({
title = '',
className = 'border-none border-gray-100 ',
className = 'border-none border-gray-100 dark:border-gray-700',
onClick = () => null,
loading = false,
variant = 'default',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function DailyPlanTask({ task, profile }: { task?: ITeamTask; profile: an

const memberInfo = useTeamMemberCard(member);
return (
<div className="flex items-center w-full bg-white border h-16 drop-shadow rounded-lg px-1 font-normal justify-between">
<div className="flex items-center w-full bg-white dark:bg-dark--theme-light border dark:border-gray-700 h-16 drop-shadow rounded-lg px-1 font-normal justify-between">
<div className="flex items-center space-x-1 w-full">
<TaskNameInfoDisplay
task={task}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { clsxm } from '@app/utils';
import { Button } from '@components/ui/button';
import { Modal } from 'lib/components'
import React from 'react'

Expand All @@ -9,13 +10,13 @@ interface ConfirmStatusChangeProps {
closeModal?: () => void;
}
export function ConfirmStatusChange({ closeModal, isOpen, newStatus, oldStatus }: ConfirmStatusChangeProps) {

const getStatusClasses = (status?: string) => {
const classes: Record<string, string> = {
Rejected: "text-red-500 border-red-500",
Approved: "text-green-500 border-green-500",
Pending: "text-orange-500 border-orange-500",
};

return status ? classes[status] || "text-gray-500 border-gray-200" : "text-gray-500 border-gray-200";
};
const newStatusClass = getStatusClasses(newStatus);
Expand All @@ -26,30 +27,54 @@ export function ConfirmStatusChange({ closeModal, isOpen, newStatus, oldStatus }
isOpen={isOpen!}
closeModal={closeModal!}
title={"Confirm Change"}
className="bg-light--theme-light dark:bg-dark--theme-light p-5 rounded-xl w-full md:w-40 md:min-w-[24rem] h-[auto] justify-start shadow-xl"
className="bg-light--theme-light text-xl0 dark:bg-dark--theme-light p-5 rounded-xl w-full md:w-40 md:min-w-[24rem] h-[auto] justify-start !shadow-2xl"
titleClass="font-bold"
>
<div className='flex flex-col gap-y-4'>
<div className='flex flex-col gap-y-4 items-center'>
<span className='font-medium'>Time entry will be changed from</span>
<div className='gap-x-2 font-medium'>
<span className={clsxm(
`${oldStatusClass}`
)}>{oldStatus}</span>
<span>to</span>
<span className={
`${newStatusClass}`
}>{newStatus}</span>
</div>
<span>Add a comment for this change that the employee will see</span>

<div className="flex flex-col">
<label className="block text-gray-500 shrink-0">Comment (optional)</label>
<textarea
placeholder="What worked on? "
className="w-full resize-none p-2 grow border border-gray-300 dark:border-slate-600 dark:bg-dark--theme-light rounded-md h-32"
/>
</div>
<StatusTransition
currentStatus={newStatus || ""}
previousStatus={oldStatus || ""}
currentStatusClass={newStatusClass}
previousStatusClass={oldStatusClass}
/>

<CommentInputArea />
<ConfirmationButtons onCancel={closeModal} />
</div>
</Modal>
)
}


const StatusTransition = ({ previousStatus, currentStatus, currentStatusClass, previousStatusClass }: { previousStatus: string; currentStatus: string; currentStatusClass: string; previousStatusClass: string }) => (
<div className="flex items-center gap-x-2 font-medium">
<span className={clsxm(previousStatusClass)}>{previousStatus}</span>
<span>to</span>
<span className={clsxm(currentStatusClass)}>{currentStatus}</span>
</div>
);

const ConfirmationButtons = ({ onConfirm, onCancel }: { onConfirm?: () => void; onCancel?: () => void }) => (
<div className="flex items-center justify-between w-full gap-x-8">
<Button onClick={onCancel} variant="outline" className="w-full">
Cancel
</Button>
<Button onClick={onConfirm} className="bg-primary dark:bg-primary-light w-full dark:text-white">
Confirm
</Button>
</div>
);

const CommentInputArea = () => (
<>
<span className="text-center text-gray-400 text-sm">Add a comment for this change that the employee will see</span>
<div className="flex flex-col w-full mt-2">
<label className="block text-gray-400 text-sm">Comment (optional)</label>
<textarea
placeholder="Add comment"
className="w-full resize-none p-2 border border-gray-300 dark:border-slate-600 dark:bg-dark--theme-light rounded-md h-32 placeholder:text-[14px]"
/>
</div>
</>
);
198 changes: 118 additions & 80 deletions apps/web/lib/features/integrations/calendar/table-time-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table"
import { ArrowUpDown, MoreHorizontal } from "lucide-react"
import { ArrowUpDownIcon, MoreHorizontal } from "lucide-react"
import { Button } from "@components/ui/button"
import {
DropdownMenu,
Expand Down Expand Up @@ -146,29 +146,27 @@ export const columns: ColumnDef<TimeSheet>[] = [
className="text-sm sm:text-base w-full text-center"
>
Project
<ArrowUpDown className="ml-2 h-4 w-4" />
<ArrowUpDownIcon className="ml-2 h-4 w-4" />
</Button>
),
cell: ({ row }) => (
<div className="flex items-start w-full">
<div className="flex items-center justify-center h-10 w-10 rounded-lg bg-primary dark:bg-primary-light text-white shadow p-2">
<span className="lowercase font-medium">ever</span>
</div>
<div className="flex flex-col items-start w-full sm:w-1/2 ml-4">
<span className="capitalize font-bold text-sm sm:text-base text-gray-800 dark:text-white leading-4 whitespace-nowrap">
{row.original.name}
</span>
<span className="capitalize font-normal text-sm sm:text-base text-gray-400 leading-4 whitespace-nowrap">
{row.original.description}
</span>
</div>
</div>
<TaskDetails
description={row.original.description}
name={row.original.name}
/>
),
},
{
accessorKey: "employee",
header: () => (
<div className="text-center w-full sm:w-96 text-sm sm:text-base">Employee</div>
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
className="text-center w-full sm:w-auto text-sm sm:text-base"
>
Employee
<ArrowUpDownIcon className="ml-2 h-4 w-4" />
</Button>
),
cell: ({ row }) => (
<div className="text-center font-medium w-full sm:w-96 text-sm sm:text-base">
Expand All @@ -178,15 +176,21 @@ export const columns: ColumnDef<TimeSheet>[] = [
},
{
accessorKey: "status",
header: () => (
<div className="text-center w-full sm:w-auto text-sm sm:text-base">Status</div>
header: ({ column }) => (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
className="text-center w-full sm:w-auto text-sm sm:text-base"
>
Status
<ArrowUpDownIcon className="ml-2 h-4 w-4" />
</Button>

),
cell: ({ row }) => {
return <SelectFilter
selectedStatus={row.original.status}

/>

return <SelectFilter
selectedStatus={row.original.status} />
}
},
{
Expand All @@ -204,28 +208,9 @@ export const columns: ColumnDef<TimeSheet>[] = [
id: "actions",
enableHiding: false,
cell: ({ row }) => {
const payment = row.original;

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0 border text-sm sm:text-base">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => navigator.clipboard.writeText(payment.id as any)}
>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<TaskActionMenu idTasks={row?.original?.id} />
);
},
},
Expand All @@ -238,12 +223,6 @@ export function DataTableTimeSheet() {
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const {
isOpen,
closeModal
} = useModal();


const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})
Expand All @@ -269,9 +248,7 @@ export function DataTableTimeSheet() {

return (
<>
<ConfirmStatusChange
closeModal={closeModal}
isOpen={isOpen} />


<div className="w-full">
<div className="rounded-md w-full ">
Expand Down Expand Up @@ -374,8 +351,11 @@ export function DataTableTimeSheet() {
)
}

function SelectFilter({ selectedStatus }: { selectedStatus?: string, }) {
const [selected, setSelected] = React.useState(selectedStatus);
function SelectFilter({ selectedStatus }: { selectedStatus?: string }) {

const { isOpen, closeModal, openModal } = useModal();
const [selected] = React.useState(selectedStatus);
const [newStatus, setNewStatus] = React.useState('');

const getColorClass = () => {
switch (selected) {
Expand All @@ -388,36 +368,94 @@ function SelectFilter({ selectedStatus }: { selectedStatus?: string, }) {
default:
return "text-gray-500 border-gray-200";
}


};


const onValueChanges = (value: string) => {
setNewStatus(value);
openModal()
}

return (
<Select
value={selected}
onValueChange={(value) => setSelected(value)}
<>

>
<SelectTrigger
className={`min-w-[120px] w-fit border border-gray-200 dark:border-gray-700 bg-transparent font-medium rounded-xl ${getColorClass()}`}
>
<SelectValue
placeholder="Select a daily"
className={getColorClass()}
/>
</SelectTrigger>
<SelectContent>
<SelectGroup className="rounded">
<SelectLabel>Status</SelectLabel>
{statusOptions.map((option, index) => (
<div key={option.value}>
<SelectItem value={option.value}>{option.label}</SelectItem>
{index < statusOptions.length - 1 && (
<div className="border w-full border-gray-100 dark:border-gray-700"></div>
)}
</div>
))}
</SelectGroup>
</SelectContent>
</Select>
<ConfirmStatusChange
closeModal={closeModal}
isOpen={isOpen}
oldStatus={selected}
newStatus={newStatus}
/>

<Select
value={selected}
onValueChange={(value) => onValueChanges(value)}
>
<SelectTrigger
className={`min-w-[120px] w-fit border border-gray-200 dark:border-gray-700 bg-transparent font-medium rounded-xl ${getColorClass()}`}
>
<SelectValue
placeholder="Select a daily"
className={getColorClass()}
/>
</SelectTrigger>
<SelectContent>
<SelectGroup className="rounded">
<SelectLabel>Status</SelectLabel>
{statusOptions.map((option, index) => (
<div key={option.value}>
<SelectItem value={option.value}>{option.label}</SelectItem>
{index < statusOptions.length - 1 && (
<div className="border w-full border-gray-100 dark:border-gray-700"></div>
)}
</div>
))}
</SelectGroup>
</SelectContent>
</Select>
</>
);
}

const TaskActionMenu = ({ idTasks }: { idTasks: any }) => {
const handleCopyPaymentId = () => navigator.clipboard.writeText(idTasks);

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0 border text-sm sm:text-base">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem onClick={handleCopyPaymentId}>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};

const TaskDetails = ({ description, name }: { description: string; name: string }) => {
return (
<div className="flex items-start w-full">
<div className="flex items-center justify-center h-10 w-10 rounded-lg bg-primary dark:bg-primary-light text-white shadow p-2">
<span className="lowercase font-medium">ever</span>
</div>
<div className="flex flex-col items-start w-full sm:w-1/2 ml-4">
<span className="capitalize font-bold text-sm sm:text-base text-gray-800 dark:text-white leading-4 whitespace-nowrap">
{name}
</span>
<span className="capitalize font-normal text-sm sm:text-base text-gray-400 leading-4 whitespace-nowrap">
{description}
</span>
</div>
</div>
);
};
Loading

0 comments on commit 7ffcd36

Please sign in to comment.