EditPack.jsx
3986 Chars | 156 Lines | 4.00 kb | Text File
Parent Directory
import React, { useEffect, useState } from 'react'
import Cards from './Cards'
import { Metadata } from './Metadata'
import { useParams } from 'react-router-dom'
import { useNavigate } from 'react-router-dom'
import Button from 'react-bootstrap/Button'
import ButtonGroup from 'react-bootstrap/ButtonGroup'
import Spinner from 'react-bootstrap/Spinner'
import { usePack } from '@/stores/pack'
import { useUser } from '@/stores/user'
import { useShallow } from 'zustand/react/shallow'
import { v4 as uuidv4 } from 'uuid'
function EditPack() {
const { displayName, packId } = useParams()
// We wrap useState around this so we can modify it (ex. adding new cards)
const [user, newPack] = useUser(useShallow((state) => [state.user, state.newPack]))
const [pack, error, loading, loadPack, filterPackCategory, addCards, letMeEdit] = usePack(
useShallow((state) => [
// Data
state.pack,
state.error,
state.loading,
state.loadPack,
state.filterPackCategory,
state.addCards,
// Editing
state.letMeEdit,
])
)
// Saving progress spinner
const [saving, startSaving] = useState(false)
// const [editingAll, setEditingAll] = useState(false)
const navigate = useNavigate()
useEffect(() => {
if (pack === undefined) {
; (async () => {
await loadPack(displayName, packId)
filterPackCategory(0)
})()
}
}, [])
useEffect(() => {
if (user?.uid !== pack?.uid && pack?.uid !== 'me') {
return (
<div className="text-center">
<h1>403</h1>
<p>You don't have permission to edit this pack.</p>
</div>
)
} else {
letMeEdit(true)
}
}, [user])
// Loading logic
if (loading) {
return (
<div className="text-center">
<h1>📎</h1>
<Spinner animation="grow" size="sm" />
</div>
)
}
// The === is very important, since it must be a boolean, not an error object
if (error === true) {
return (
<div className="text-center">
<h1>404</h1>
<p>Sorry, this pack doesn't exist.</p>
</div>
)
}
if (error) {
return (
<div className="text-center">
<h1>403</h1>
<p>This pack exists, but it hasn't been published.</p>
<code>{error.toString()}</code>
</div>
)
}
async function saveCards(viewMode = false) {
startSaving(true)
await newPack(packId, pack)
if (viewMode) {
navigate(`/view/${pack.author}/${pack.uuid}`)
} else {
// This isn't a stopgap for async, it just shows the saving spinner,
// providing feedback to the user
setTimeout(() => {
startSaving(false)
}, '200')
}
}
function newCards() {
// Add new terms
addCards({
term: '',
definition: '',
category: 'default',
uuid: uuidv4(),
})
}
return (
<div id="packRoot" className="mx-auto mb-5 border border-2 p-4 rounded-3 pack">
<Metadata editing />
<div id="packContentContainer" className="mt-3 border border-2 rounded-3">
{/* <AnimatePresence> */}
{pack.content.map((cards, index) => (
<Cards index={index} edit={true} key={cards.uuid + index} />
))}
{/* </AnimatePresence> */}
</div>
<div id="parentToolbar" className="d-flex justify-content-between fixed-bottom">
<ButtonGroup className="mx-auto fw-bold" id="bottomToolbar">
<Button variant="light" onClick={() => saveCards()} className="p-3">
{saving ? (
<Spinner animation="border" variant="dark" size="sm" />
) : (
'💾 Save'
)}
</Button>
<Button variant="light" onClick={newCards} className="p-3">
âž• Add Cards
</Button>
{/* <LinkContainer to={`/view/${pack.author}/${pack.uuid}`}> */}
<Button variant="light" onClick={() => saveCards(true)} className="p-3">
{saving ? 'Saving...' : '↩ Return'}
</Button>
{/* </LinkContainer> */}
</ButtonGroup>
</div>
</div>
)
}
export default EditPack