add update/delete/edit/add deck functionality

This commit is contained in:
2023-10-09 13:25:00 +02:00
parent 7d0ed69481
commit 065e23239e
5 changed files with 112 additions and 10 deletions

View File

@@ -29,6 +29,7 @@ export const DeckDialog = ({
}) })
const onSubmit = handleSubmit(data => { const onSubmit = handleSubmit(data => {
onConfirm(data) onConfirm(data)
dialogProps.onOpenChange?.(false)
reset() reset()
}) })
const handleCancel = () => { const handleCancel = () => {

View File

@@ -0,0 +1,5 @@
.iconsContainer {
display: flex;
gap: 10px;
align-items: center;
}

View File

@@ -1,6 +1,10 @@
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import s from './decks-table.module.scss'
import { Edit2Outline, PlayCircleOutline, TrashOutline } from '@/assets'
import { import {
Button,
Column, Column,
Table, Table,
TableBody, TableBody,
@@ -11,7 +15,6 @@ import {
} from '@/components' } from '@/components'
import { Deck } from '@/services/decks' import { Deck } from '@/services/decks'
import { formatDate } from '@/utils' import { formatDate } from '@/utils'
const columns: Column[] = [ const columns: Column[] = [
{ {
key: 'name', key: 'name',
@@ -37,8 +40,14 @@ const columns: Column[] = [
type Props = { type Props = {
decks: Deck[] | undefined decks: Deck[] | undefined
onDeleteClick: (id: string) => void
currentUserId: string
onEditClick: (id: string) => void
} }
export const DecksTable = ({ decks }: Props) => { export const DecksTable = ({ decks, onEditClick, onDeleteClick, currentUserId }: Props) => {
const handleEditClick = (id: string) => () => onEditClick(id)
const handleDeleteClick = (id: string) => () => onDeleteClick(id)
return ( return (
<Table> <Table>
<TableHeader columns={columns} /> <TableHeader columns={columns} />
@@ -53,7 +62,23 @@ export const DecksTable = ({ decks }: Props) => {
<TableCell>{deck.cardsCount}</TableCell> <TableCell>{deck.cardsCount}</TableCell>
<TableCell>{formatDate(deck.updated)}</TableCell> <TableCell>{formatDate(deck.updated)}</TableCell>
<TableCell>{deck.author.name}</TableCell> <TableCell>{deck.author.name}</TableCell>
<TableCell>...</TableCell> <TableCell>
<div className={s.iconsContainer}>
<Button variant={'icon'} as={Link} to={`/decks/${deck.id}/learn`}>
<PlayCircleOutline />
</Button>
{deck.author.id === currentUserId && (
<>
<Button variant={'icon'} onClick={handleEditClick(deck.id)}>
<Edit2Outline />
</Button>
<Button variant={'icon'} onClick={handleDeleteClick(deck.id)}>
<TrashOutline />
</Button>
</>
)}
</div>
</TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>

View File

@@ -3,10 +3,18 @@ import { useState } from 'react'
import s from './decks-page.module.scss' import s from './decks-page.module.scss'
import { Button, Page, Slider, TextField, Typography } from '@/components' import { Button, Page, Slider, TextField, Typography } from '@/components'
import { DeckDialog } from '@/components/decks/deck-dialog'
import { DecksTable } from '@/components/decks/decks-table' import { DecksTable } from '@/components/decks/decks-table'
import { DeleteDeckDialog } from '@/components/decks/delete-deck-dialog'
import { Pagination } from '@/components/ui/pagination' import { Pagination } from '@/components/ui/pagination'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Tab, useGetDecksQuery } from '@/services/decks' import {
Tab,
useCreateDeckMutation,
useDeleteDeckMutation,
useGetDecksQuery,
useUpdateDeckMutation,
} from '@/services/decks'
import { import {
selectDecksCurrentPage, selectDecksCurrentPage,
selectDecksCurrentTab, selectDecksCurrentTab,
@@ -15,9 +23,15 @@ import {
selectDecksSearch, selectDecksSearch,
} from '@/services/decks/decks.selectors.ts' } from '@/services/decks/decks.selectors.ts'
import { decksSlice } from '@/services/decks/decks.slice.ts' import { decksSlice } from '@/services/decks/decks.slice.ts'
import { useAppDispatch, useAppSelector } from '@/services/store.ts' import { useAppDispatch, useAppSelector } from '@/services/store'
export const DecksPage = () => { export const DecksPage = () => {
const [showCreateModal, setShowCreateModal] = useState(false)
const [deckToDeleteId, setDeckToDeleteId] = useState<string | null>(null)
const [deckToEditId, setDeckToEditId] = useState<string | null>(null)
const showEditModal = !!deckToEditId
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const currentPage = useAppSelector(selectDecksCurrentPage) const currentPage = useAppSelector(selectDecksCurrentPage)
const minCards = useAppSelector(selectDecksMinCards) const minCards = useAppSelector(selectDecksMinCards)
@@ -30,14 +44,19 @@ export const DecksPage = () => {
const setSearch = (search: string) => dispatch(decksSlice.actions.setSearch(search)) const setSearch = (search: string) => dispatch(decksSlice.actions.setSearch(search))
const setCurrentTab = (tab: Tab) => dispatch(decksSlice.actions.setCurrentTab(tab)) const setCurrentTab = (tab: Tab) => dispatch(decksSlice.actions.setCurrentTab(tab))
const resetFilters = () => {
dispatch(decksSlice.actions.resetFilters())
setRangeValue([0, decks?.maxCardsCount || undefined])
}
const [rangeValue, setRangeValue] = useState([minCards, maxCards]) const [rangeValue, setRangeValue] = useState([minCards, maxCards])
const handleSliderCommitted = (value: number[]) => { const handleSliderCommitted = (value: number[]) => {
setMinCards(value[0]) setMinCards(value[0])
setMaxCards(value[1]) setMaxCards(value[1])
} }
const currentUserId = 'f2be95b9-4d07-4751-a775-bd612fc9553a'
const authorId = currentTab === 'my' ? 'f2be95b9-4d07-4751-a775-bd612fc9553a' : undefined const authorId = currentTab === 'my' ? currentUserId : undefined
const { data: decks } = useGetDecksQuery({ const { data: decks } = useGetDecksQuery({
currentPage, currentPage,
@@ -47,14 +66,51 @@ export const DecksPage = () => {
authorId, authorId,
}) })
const showConfirmDeleteModal = !!deckToDeleteId
const deckToDeleteName = decks?.items?.find(deck => deck.id === deckToDeleteId)?.name
const deckToEdit = decks?.items?.find(deck => deck.id === deckToEditId)
const [createDeck] = useCreateDeckMutation()
const [deleteDeck] = useDeleteDeckMutation()
const [updateDeck] = useUpdateDeckMutation()
const openCreateModal = () => setShowCreateModal(true)
if (!decks) return <div>loading...</div> if (!decks) return <div>loading...</div>
return ( return (
<Page> <Page>
<DeleteDeckDialog
open={showConfirmDeleteModal}
onOpenChange={() => setDeckToDeleteId(null)}
deckName={deckToDeleteName ?? 'Selected deck'}
onCancel={() => setDeckToDeleteId(null)}
onConfirm={() => {
deleteDeck({ id: deckToDeleteId ?? '' })
setDeckToDeleteId(null)
}}
/>
<DeckDialog
open={showEditModal}
onOpenChange={() => setDeckToEditId(null)}
onConfirm={data => {
if (!deckToEditId) return
updateDeck({ id: deckToEditId, ...data })
}}
defaultValues={deckToEdit}
key={deckToEditId}
/>
<div className={s.root}> <div className={s.root}>
<div className={s.header}> <div className={s.header}>
<Typography variant="large">Decks</Typography> <Typography variant="large">Decks</Typography>
<Button>Add new deck</Button> <Button onClick={openCreateModal}>Add new deck</Button>
<DeckDialog
open={showCreateModal}
onOpenChange={setShowCreateModal}
onConfirm={createDeck}
onCancel={() => setShowCreateModal(false)}
/>
</div> </div>
<div className={s.filters}> <div className={s.filters}>
<TextField placeholder="Search" search value={search} onValueChange={setSearch} /> <TextField placeholder="Search" search value={search} onValueChange={setSearch} />
@@ -71,9 +127,16 @@ export const DecksPage = () => {
min={0} min={0}
max={decks?.maxCardsCount || 0} max={decks?.maxCardsCount || 0}
/> />
<Button variant={'secondary'}>Clear filters</Button> <Button variant={'secondary'} onClick={resetFilters}>
Clear filters
</Button>
</div> </div>
<DecksTable decks={decks?.items} /> <DecksTable
decks={decks?.items}
onDeleteClick={setDeckToDeleteId}
onEditClick={setDeckToEditId}
currentUserId={currentUserId}
/>
<Pagination <Pagination
count={decks?.pagination?.totalPages || 1} count={decks?.pagination?.totalPages || 1}
page={currentPage} page={currentPage}

View File

@@ -63,4 +63,12 @@ export type GetDecksArgs = {
itemsPerPage?: number itemsPerPage?: number
} }
export type CreateDeckArgs = {
name: string
isPrivate?: boolean
cover?: string
}
export type UpdateDeckArgs = Partial<CreateDeckArgs> & { id: Deck['id'] }
export type Tab = 'all' | 'my' export type Tab = 'all' | 'my'