Skip to content

Commit

Permalink
Merge pull request #1477 from rockingrohit9639/feature/assets-bulk-ac…
Browse files Browse the repository at this point in the history
…tions

Feature/assets bulk actions
  • Loading branch information
DonKoko authored Dec 10, 2024
2 parents b761af7 + cbff2a6 commit 992b17f
Show file tree
Hide file tree
Showing 17 changed files with 931 additions and 167 deletions.
14 changes: 12 additions & 2 deletions app/atoms/bulk-update-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { BulkDialogType } from "~/components/bulk-update-dialog/bulk-update
* This atom is responsible for holding the open state for dialogs
* Open Dialog must be open at a time
*/
export const bulkDialogAtom = atom<Record<BulkDialogType, boolean>>({
const DEFAULT_STATE = {
location: false,
category: false,
"assign-custody": false,
Expand All @@ -19,7 +19,17 @@ export const bulkDialogAtom = atom<Record<BulkDialogType, boolean>>({
cancel: false,
available: false,
unavailable: false,
});
bookings: false,
"booking-exist": false,
};

export const bulkDialogAtom =
atom<Record<BulkDialogType, boolean>>(DEFAULT_STATE);

/** Reset the atom when it mounts */
bulkDialogAtom.onMount = (setAtom) => {
setAtom(DEFAULT_STATE);
};

/**
* This will trigger the Dialog to open for a particular key
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { useEffect, useState } from "react";
import type { Asset, Booking } from "@prisma/client";
import { useNavigate } from "@remix-run/react";
import { useAtomValue } from "jotai";
import { useZorm } from "react-zorm";
import { z } from "zod";
import { bulkDialogAtom } from "~/atoms/bulk-update-dialog";
import { selectedBulkItemsAtom } from "~/atoms/list";
import { BulkUpdateDialogContent } from "~/components/bulk-update-dialog/bulk-update-dialog";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/forms/select";
import { Button } from "~/components/shared/button";
import When from "~/components/when/when";

export const addAssetsToExistingBookingSchema = z.object({
id: z
.string({ required_error: "Please select booking." })
.min(1, "Please select booking."),
assetsIds: z.string().array().min(1, "Please select at least one asset."),
addOnlyRestAssets: z.coerce.boolean().optional().nullable(),
});

type BookingWithDates = Booking & {
displayFrom: string;
displayTo: string;
};

export default function AddAssetsToExistingBookingDialog() {
const navigate = useNavigate();

const zo = useZorm(
"AddAssetsToExistingBooking",
addAssetsToExistingBookingSchema
);

const selectedAssets = useAtomValue(selectedBulkItemsAtom);
const bulkDialogOpenState = useAtomValue(bulkDialogAtom);

const [isFetchingBookings, setIsFetchingBookings] = useState(false);
const [bookings, setBookings] = useState<BookingWithDates[]>([]);

const isDialogOpen = bulkDialogOpenState["booking-exist"] === true;

useEffect(() => {
if (isDialogOpen) {
setIsFetchingBookings(true);

fetch("/api/bookings/get-all")
.then((response) => response.json())
.then((data: { bookings: BookingWithDates[] }) => {
setBookings(data.bookings);
})
.finally(() => {
setIsFetchingBookings(false);
});
}
}, [isDialogOpen]);

return (
<BulkUpdateDialogContent
ref={zo.ref}
type="booking-exist"
arrayFieldId="assetsIds"
title="Add to existing booking"
description={`Add selected(${selectedAssets.length}) assets to existing booking.`}
actionUrl="/api/assets/add-to-booking"
className="lg:w-[600px]"
skipCloseOnSuccess
>
{({
disabled,
handleCloseDialog,
fetcherData,
fetcherError,
fetcherErrorAdditionalData,
}) => (
<>
{/* Handling the initial state of the dialog */}
<When truthy={!fetcherData?.success}>
<div className="max-h-[calc(100vh_-_200px)] overflow-auto">
<Select name="id" disabled={isFetchingBookings || disabled}>
<SelectTrigger className="mb-4">
<SelectValue
placeholder={
isFetchingBookings
? "Fetching bookings..."
: "Select booking"
}
/>
</SelectTrigger>
<SelectContent>
{bookings.map((booking) => (
<SelectItem asChild key={booking.id} value={booking.id}>
<div className="flex flex-col items-start gap-1 text-black">
<div className="semi-bold max-w-[250px] truncate">
{booking.name}
</div>
<div className="text-xs text-gray-500">
{booking.displayFrom} - {booking.displayTo}
</div>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
<When truthy={!!zo.errors.id()?.message}>
<p className="mb-4 text-sm text-error-500">
{zo.errors.id()?.message}
</p>
</When>

<When truthy={!!fetcherError || !!fetcherErrorAdditionalData}>
<div className="mb-4 rounded-md border border-gray-300 bg-gray-25 p-2">
<When truthy={!!fetcherError}>
<p>{fetcherError}</p>
</When>
<When
truthy={
!!fetcherErrorAdditionalData &&
fetcherErrorAdditionalData?.alreadyAddedAssets?.length
}
>
<div className="mt-4">
<p>Already added assets are : </p>
<ul className="mb-2 list-inside list-disc">
{fetcherErrorAdditionalData?.alreadyAddedAssets.map(
(asset: Pick<Asset, "id" | "title">) => (
<li key={asset.id}>{asset.title}</li>
)
)}
</ul>

<input
type="hidden"
name="addOnlyRestAssets"
value="true"
/>

<When
truthy={!fetcherErrorAdditionalData?.allAssetsInBooking}
>
<Button className="w-full" variant="secondary">
Add only the rest of the assets
</Button>
</When>
</div>
</When>
</div>
</When>

<div className="flex items-center gap-3">
<Button
variant="secondary"
width="full"
disabled={disabled}
onClick={handleCloseDialog}
>
Cancel
</Button>
<Button
type="submit"
variant="primary"
width="full"
disabled={disabled}
>
Confirm
</Button>
</div>
</div>
</When>

{/* Handling the after success state of the dialog */}
<When truthy={!!fetcherData?.success}>
<div>
<div className="mb-4 rounded-md border border-success-500 p-2 text-success-500">
<h5 className="text-success-500">Booking updated</h5>
<p>
The assets you selected have been added to the booking. Do you
want to add more or view the booking?
</p>
</div>

<div className="flex items-center gap-3">
<Button
type="button"
variant="secondary"
width="full"
disabled={disabled}
onClick={handleCloseDialog}
>
Add more
</Button>
<Button
type="button"
variant="primary"
width="full"
disabled={disabled}
onClick={() => {
navigate(`/bookings/${fetcherData?.bookingId}`);
}}
>
View booking
</Button>
</div>
</div>
</When>
</>
)}
</BulkUpdateDialogContent>
);
}
Loading

0 comments on commit 992b17f

Please sign in to comment.