-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into dependabot/npm_and_yarn/vite-5.4.6
- Loading branch information
Showing
53 changed files
with
2,008 additions
and
232 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { atom } from "jotai"; | ||
import type { AssetWithBooking } from "~/routes/_layout+/bookings.$bookingId.add-assets"; | ||
import type { KitForBooking } from "~/routes/_layout+/bookings.$bookingId.add-kits"; | ||
|
||
export type ScanListItems = { | ||
[key: string]: ScanListItem; | ||
}; | ||
|
||
export type ScanListItem = | ||
| { | ||
data?: AssetWithBooking | KitForBooking; | ||
error?: string; | ||
type?: "asset" | "kit"; | ||
} | ||
| undefined; | ||
|
||
/*********************** | ||
* Scanned QR Id Atom * | ||
* | ||
* The data is structured in a object where: | ||
* - key: qrId | ||
* - value: asset | ||
* | ||
***********************/ | ||
|
||
export const scannedItemsAtom = atom<ScanListItems>({}); | ||
|
||
/** Get an array of the scanned items ids */ | ||
export const scannedItemsIdsAtom = atom((get) => | ||
Object.values(get(scannedItemsAtom)).map((item) => item?.data?.id) | ||
); | ||
|
||
// Add item to object with value `undefined` (just receives the key) | ||
export const addScannedItemAtom = atom( | ||
null, | ||
(get, set, qrId: string, error?: string) => { | ||
const currentItems = get(scannedItemsAtom); | ||
if (!currentItems[qrId]) { | ||
/** Set can optionally receive error. If it does, add it to the item. | ||
* This is used for errors that are related to the QR code itself, not the item. | ||
*/ | ||
set(scannedItemsAtom, { | ||
[qrId]: error | ||
? { | ||
error: error, | ||
} | ||
: undefined, // Add the new entry at the start | ||
...currentItems, // Spread the rest of the existing items | ||
}); | ||
} | ||
} | ||
); | ||
|
||
// Update item based on key | ||
export const updateScannedItemAtom = atom( | ||
null, | ||
(get, set, { qrId, item }: { qrId: string; item: ScanListItem }) => { | ||
const currentItems = get(scannedItemsAtom); | ||
|
||
// Check if the item already exists; if it does, skip the update | ||
if (!item || currentItems[qrId]) { | ||
return; // Skip the update if the item is already present | ||
} | ||
|
||
if ((item && item?.data && item?.type) || item?.error) { | ||
set(scannedItemsAtom, { | ||
...currentItems, | ||
[qrId]: item, | ||
}); | ||
} | ||
} | ||
); | ||
|
||
// Remove item based on key | ||
export const removeScannedItemAtom = atom(null, (get, set, qrId: string) => { | ||
const currentItems = get(scannedItemsAtom); | ||
const { [qrId]: _, ...rest } = currentItems; // Removes the key | ||
set(scannedItemsAtom, rest); | ||
}); | ||
|
||
// Remove multiple items based on key array | ||
export const removeMultipleScannedItemsAtom = atom( | ||
null, | ||
(get, set, qrIds: string[]) => { | ||
const currentItems = get(scannedItemsAtom); | ||
const updatedItems = { ...currentItems }; | ||
qrIds.forEach((qrId) => { | ||
delete updatedItems[qrId]; | ||
}); | ||
set(scannedItemsAtom, updatedItems); | ||
} | ||
); | ||
|
||
// Remove items based on asset id | ||
export const removeScannedItemsByAssetIdAtom = atom( | ||
null, | ||
(get, set, ids: string[]) => { | ||
const currentItems = get(scannedItemsAtom); | ||
const updatedItems = { ...currentItems }; | ||
Object.entries(currentItems).forEach(([qrId, item]) => { | ||
if (item?.data?.id && ids.includes(item?.data?.id)) { | ||
delete updatedItems[qrId]; | ||
} | ||
}); | ||
set(scannedItemsAtom, updatedItems); | ||
} | ||
); | ||
|
||
// Clear all items | ||
export const clearScannedItemsAtom = atom(null, (_get, set) => { | ||
set(scannedItemsAtom, {}); // Resets the atom to an empty object | ||
}); | ||
|
||
/*******************************/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { useEffect } from "react"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import { useZorm } from "react-zorm"; | ||
import { z } from "zod"; | ||
import { BulkUpdateDialogContent } from "../bulk-update-dialog/bulk-update-dialog"; | ||
import { Button } from "../shared/button"; | ||
import { TagsAutocomplete, type TagSuggestion } from "../tag/tags-autocomplete"; | ||
|
||
export const BulkAssignTagsSchema = z.object({ | ||
assetIds: z.array(z.string()).min(1), | ||
tags: z.string(), | ||
}); | ||
|
||
export default function BulkAssignTagsDialog() { | ||
const zo = useZorm("BulkAssignTags", BulkAssignTagsSchema); | ||
|
||
const fetcher = useFetcher(); | ||
// @ts-ignore | ||
const suggestions = fetcher.data?.filters.map((tagResponse) => ({ | ||
label: tagResponse.name, | ||
value: tagResponse.id, | ||
})) as TagSuggestion[]; | ||
|
||
useEffect(() => { | ||
fetcher.submit( | ||
{ | ||
name: "tag", | ||
queryKey: "name", | ||
queryValue: "", | ||
}, | ||
{ | ||
method: "GET", | ||
action: "/api/model-filters", | ||
} | ||
); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
return ( | ||
<BulkUpdateDialogContent | ||
ref={zo.ref} | ||
type="tag-add" | ||
title="Assign tags to assets" | ||
description="Assign tags to selected assets. Assets that already have any of the selected tags, will be skipped." | ||
actionUrl="/api/assets/bulk-assign-tags" | ||
arrayFieldId="assetIds" | ||
> | ||
{({ disabled, handleCloseDialog, fetcherError }) => ( | ||
<div className="modal-content-wrapper"> | ||
<div className="relative z-50 mb-8"> | ||
<TagsAutocomplete existingTags={[]} suggestions={suggestions} /> | ||
|
||
{zo.errors.tags()?.message ? ( | ||
<p className="text-sm text-error-500"> | ||
{zo.errors.tags()?.message} | ||
</p> | ||
) : null} | ||
{fetcherError ? ( | ||
<p className="text-sm text-error-500">{fetcherError}</p> | ||
) : null} | ||
</div> | ||
|
||
<div className="flex gap-3"> | ||
<Button | ||
variant="secondary" | ||
width="full" | ||
disabled={disabled} | ||
onClick={handleCloseDialog} | ||
> | ||
Cancel | ||
</Button> | ||
<Button variant="primary" width="full" disabled={disabled}> | ||
Confirm | ||
</Button> | ||
</div> | ||
</div> | ||
)} | ||
</BulkUpdateDialogContent> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { useEffect } from "react"; | ||
import { useFetcher } from "@remix-run/react"; | ||
import { useZorm } from "react-zorm"; | ||
import { z } from "zod"; | ||
import { BulkUpdateDialogContent } from "../bulk-update-dialog/bulk-update-dialog"; | ||
import { Button } from "../shared/button"; | ||
import { TagsAutocomplete, type TagSuggestion } from "../tag/tags-autocomplete"; | ||
|
||
export const BulkRemoveTagsSchema = z.object({ | ||
assetIds: z.array(z.string()).min(1), | ||
tags: z.string(), | ||
}); | ||
|
||
export default function BulkRemoveTagsDialog() { | ||
const zo = useZorm("BulkRemoveTags", BulkRemoveTagsSchema); | ||
|
||
const fetcher = useFetcher(); | ||
// @ts-ignore | ||
const suggestions = fetcher.data?.filters.map((tagResponse) => ({ | ||
label: tagResponse.name, | ||
value: tagResponse.id, | ||
})) as TagSuggestion[]; | ||
|
||
useEffect(() => { | ||
fetcher.submit( | ||
{ | ||
name: "tag", | ||
queryKey: "name", | ||
queryValue: "", | ||
}, | ||
{ | ||
method: "GET", | ||
action: "/api/model-filters", | ||
} | ||
); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
return ( | ||
<BulkUpdateDialogContent | ||
ref={zo.ref} | ||
type="tag-remove" | ||
title="Remove tags from assets" | ||
description="Remove tags to selected assets. Assets that don't have any of the selected tags, will be skipped." | ||
actionUrl="/api/assets/bulk-assign-tags?remove=true" | ||
arrayFieldId="assetIds" | ||
> | ||
{({ disabled, handleCloseDialog, fetcherError }) => ( | ||
<div className="modal-content-wrapper"> | ||
<div className="relative z-50 mb-8"> | ||
<TagsAutocomplete existingTags={[]} suggestions={suggestions} /> | ||
|
||
{zo.errors.tags()?.message ? ( | ||
<p className="text-sm text-error-500"> | ||
{zo.errors.tags()?.message} | ||
</p> | ||
) : null} | ||
{fetcherError ? ( | ||
<p className="text-sm text-error-500">{fetcherError}</p> | ||
) : null} | ||
</div> | ||
|
||
<div className="flex gap-3"> | ||
<Button | ||
variant="secondary" | ||
width="full" | ||
disabled={disabled} | ||
onClick={handleCloseDialog} | ||
> | ||
Cancel | ||
</Button> | ||
<Button variant="primary" width="full" disabled={disabled}> | ||
Confirm | ||
</Button> | ||
</div> | ||
</div> | ||
)} | ||
</BulkUpdateDialogContent> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.