Skip to content

Commit

Permalink
allows selecting multiple experiences to add to a playlist
Browse files Browse the repository at this point in the history
  • Loading branch information
brollin committed Nov 7, 2024
1 parent b40ab3a commit 9966661
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 28 deletions.
52 changes: 39 additions & 13 deletions src/components/ExperiencesTable/ExperiencesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { observer } from "mobx-react-lite";
import {
Button,
Checkbox,
IconButton,
Table,
TableContainer,
Expand All @@ -15,30 +16,40 @@ import { action } from "mobx";
import { FaTrashAlt } from "react-icons/fa";
import { Experience } from "@/src/types/Experience";

type ExperiencesTableProps = {
experiencesAndUsers: { user: { username: string }; experience: Experience }[];
omitIds?: number[];
onClickExperience?: (experience: Experience) => void;
selectable?: boolean;
selectedExperienceIds?: number[];
setSelectedExperienceIds?: (experiences: number[]) => void;
};

export const ExperiencesTable = observer(function ExperiencesTable({
experiencesAndUsers,
onLoadExperience,
onClickExperience,
omitIds,
selectable,
selectedExperiences,
setSelectedExperiences,
}: {
experiencesAndUsers: { user: { username: string }; experience: Experience }[];
onLoadExperience: (experience: Experience) => void;
omitIds?: number[];
// TODO: implement selectable experiences in the table
selectable?: boolean;
selectedExperiences?: string[];
setSelectedExperiences?: (experiences: string[]) => void;
}) {
selectedExperienceIds,
setSelectedExperienceIds,
}: ExperiencesTableProps) {
const store = useStore();
const { username } = store;

const toggleExperienceIdSelection = (id: number) => {
setSelectedExperienceIds?.(
selectedExperienceIds?.includes(id)
? selectedExperienceIds.filter((selectedId) => selectedId !== id)
: [...(selectedExperienceIds ?? []), id]
);
};

return (
<TableContainer>
<Table size="sm" colorScheme="blue">
<Thead>
<Tr>
{selectable && <Th />}
<Th>Name</Th>
<Th>Author</Th>
<Th>Song</Th>
Expand All @@ -50,13 +61,28 @@ export const ExperiencesTable = observer(function ExperiencesTable({
.filter(({ experience }) => !omitIds?.includes(experience.id!))
.map(({ user, experience }) => (
<Tr key={experience.id}>
{selectable && (
<Td>
<Checkbox
isChecked={selectedExperienceIds?.includes(
experience.id!
)}
onChange={() =>
toggleExperienceIdSelection(experience.id!)
}
/>
</Td>
)}
<Td>
<Button
ml={-3}
size="md"
height={8}
variant="solid"
onClick={() => onLoadExperience(experience)}
onClick={() =>
onClickExperience?.(experience) ??
toggleExperienceIdSelection(experience.id!)
}
>
{experience.name}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Menu/OpenExperienceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const OpenExperienceModal = observer(function OpenExperienceModal() {
{!isPending && (
<ExperiencesTable
experiencesAndUsers={experiencesAndUsers}
onLoadExperience={action(async (experience) => {
onClickExperience={action(async (experience) => {
setIsLoadingNewExperience(true);
await experienceStore.load(experience.name);
setIsLoadingNewExperience(false);
Expand Down
42 changes: 29 additions & 13 deletions src/components/PlaylistEditor/AddExperienceModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { observer } from "mobx-react-lite";
import {
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Spinner,
Expand All @@ -27,6 +29,9 @@ export const AddExperienceModal = observer(function AddExperienceModal({
const { username, uiStore } = store;

const [viewingAllExperiences, setViewingAllExperiences] = useState(false);
const [selectedExperienceIds, setSelectedExperienceIds] = useState<number[]>(
[]
);

const { isPending, isError, experiencesAndUsers } = useExperiencesAndUsers({
username: viewingAllExperiences ? undefined : username,
Expand All @@ -37,9 +42,10 @@ export const AddExperienceModal = observer(function AddExperienceModal({

if (isError) return null;

const onClose = action(
() => (uiStore.showingPlaylistAddExperienceModal = false)
);
const onClose = action(() => {
setSelectedExperienceIds([]);
uiStore.showingPlaylistAddExperienceModal = false;
});

return (
<Modal
Expand Down Expand Up @@ -69,20 +75,30 @@ export const AddExperienceModal = observer(function AddExperienceModal({
{!isPending && (
<ExperiencesTable
experiencesAndUsers={experiencesAndUsers}
onLoadExperience={action((experience) => {
savePlaylist({
...playlist,
orderedExperienceIds: [
...playlist.orderedExperienceIds,
experience.id!,
],
});
onClose();
})}
omitIds={playlist.orderedExperienceIds}
selectable
selectedExperienceIds={selectedExperienceIds}
setSelectedExperienceIds={setSelectedExperienceIds}
/>
)}
</ModalBody>
<ModalFooter>
<Button
isDisabled={!selectedExperienceIds.length || isPending}
onClick={action(() => {
savePlaylist({
...playlist,
orderedExperienceIds: [
...playlist.orderedExperienceIds,
...selectedExperienceIds,
],
});
onClose();
})}
>
{isPending ? <Spinner /> : "Add"}
</Button>
</ModalFooter>
<ModalCloseButton />
</ModalContent>
</Modal>
Expand Down
2 changes: 1 addition & 1 deletion src/server/routers/experienceRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const experienceRouter = router({
throw new TRPCError({
code: "FORBIDDEN",
message:
'You do not have permission to save this experience. Save a copy with "File > Save as" instead.',
'You do not have permission to edit this experience. Save a copy with "File > Save as" instead.',
});
}

Expand Down

0 comments on commit 9966661

Please sign in to comment.