From 58076e90e73242b693365c526d154845ef04faf8 Mon Sep 17 00:00:00 2001 From: JunHam Date: Wed, 13 Aug 2025 23:04:13 +0800 Subject: [PATCH 01/21] Added fetchCollection for artefact editor --- src/pages/ArtefactEditor.jsx | 71 ++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index e1f30c5..0ad9bbf 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -1,5 +1,5 @@ import { Box, Flex, Text, Image } from "@chakra-ui/react"; -import { useParams } from 'react-router-dom'; +import { useParams, useNavigate } from 'react-router-dom'; import { useEffect, useRef, useState } from "react"; import { useSelector } from "react-redux"; import ToastWizard from "../components/toastWizard"; @@ -10,9 +10,70 @@ import EditorCard from "../components/DataStudio/editorCard"; import { FaCircleArrowLeft } from "react-icons/fa6"; function ArtefactEditor() { - const { artID } = useParams(); + const { colID, artID } = useParams(); const [metadata, setMetadata] = useState(null); + const [collection, setCollection] = useState(null); const { loaded } = useSelector(state => state.auth); + const navigate = useNavigate(); + + // Collection items fetching function + const fetchCollection = async () => { + try { + const response = await server.get(`/cdn/collectionMemberIDs/${colID}`); + + if (response.data instanceof JSONResponse) { + if (response.data.isErrorStatus()) { + const errObject = { + response: { + data: response.data + } + }; + throw new Error(errObject); + } + + // Success case + setCollection(response.data.raw.data) + } else { + throw new Error("Unexpected response format"); + } + } catch (err) { + if (err.response && err.response.data instanceof JSONResponse) { + console.log("Error response in login request:", err.response.data.fullMessage()); + if (err.response.data.userErrorType()) { + ToastWizard.standard( + "error", + "An Error Occured", + err.response.data.message || "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); + } else { + ToastWizard.standard( + "error", + "An Error Occured", + "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); + } + } else { + console.log("Unexpected error in fetching collection:", err); + ToastWizard.standard( + "error", + "An Error Occured", + "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); + } + } + } // Metadata fetching function const fetchMetadata = async () => { @@ -77,6 +138,7 @@ function ArtefactEditor() { // Fetch metadata if user is loaded useEffect(() => { if (loaded) { + fetchCollection() fetchMetadata() } }, [loaded]); @@ -86,10 +148,13 @@ function ArtefactEditor() { return } + console.log(collection) + console.log(metadata) + return ( - + navigate(-1)} size={40} color='darkBlue' /> Data Studio {metadata.name} From 2c72b3cbcd721b1920ae557e00462ff08b73039d Mon Sep 17 00:00:00 2001 From: JunHam Date: Wed, 13 Aug 2025 23:22:39 +0800 Subject: [PATCH 02/21] Added colID and artID check for artefact editor --- src/pages/ArtefactEditor.jsx | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index 0ad9bbf..a35011f 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -15,6 +15,7 @@ function ArtefactEditor() { const [collection, setCollection] = useState(null); const { loaded } = useSelector(state => state.auth); const navigate = useNavigate(); + const [isInvalid, setIsInvalid] = useState(false) // Collection items fetching function const fetchCollection = async () => { @@ -143,14 +144,30 @@ function ArtefactEditor() { } }, [loaded]); + useEffect(() => { + if (collection && metadata) { + const isInCollection = + (Array.isArray(collection.mmIDs) && collection.mmIDs.includes(artID)) || + (collection.members && Object.keys(collection.members).includes(artID)); + + if (!isInCollection) { + setIsInvalid(true); + setTimeout(() => { + ToastWizard.standard( + "error", + "An Error Occured", + "Artefact and collection does not exist." + ); + }, 0); + } + } + }, [collection, metadata, artID]); + // Show loading spinner while data is being fetched - if (!metadata) { + if (!metadata || !collection || isInvalid) { return } - console.log(collection) - console.log(metadata) - return ( From c49df20c2b9756433bde953e9377fccf90971b84 Mon Sep 17 00:00:00 2001 From: JunHam Date: Wed, 13 Aug 2025 23:38:19 +0800 Subject: [PATCH 03/21] Added scrolling for artefact editor --- src/pages/ArtefactEditor.jsx | 83 ++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index a35011f..7d8bc9b 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -15,7 +15,62 @@ function ArtefactEditor() { const [collection, setCollection] = useState(null); const { loaded } = useSelector(state => state.auth); const navigate = useNavigate(); - const [isInvalid, setIsInvalid] = useState(false) + const [isInvalid, setIsInvalid] = useState(false); + const [isNavigating, setIsNavigating] = useState(false); + + // Get the list of artifact IDs from collection data + const getArtifactIds = () => { + if (!collection) return []; + + // Handle array format (mmIDs) + if (Array.isArray(collection.mmIDs)) { + return collection.mmIDs; + } + + // Handle object format (members) + if (collection.members && typeof collection.members === 'object') { + return Object.keys(collection.members); + } + + return []; + }; + + // Get current artifact index and navigation info + const getNavigationInfo = () => { + const artifactIds = getArtifactIds(); + const currentIndex = artifactIds.indexOf(artID); + + return { + artifactIds, + currentIndex, + isFirst: currentIndex <= 0, + isLast: currentIndex >= artifactIds.length - 1, + hasPrevious: currentIndex > 0, + hasNext: currentIndex < artifactIds.length - 1 + }; + }; + + // Navigate to previous artifact + const navigateToPrevious = () => { + const { artifactIds, currentIndex, hasPrevious } = getNavigationInfo(); + + if (hasPrevious) { + setIsNavigating(true); + const previousArtId = artifactIds[currentIndex - 1]; + navigate(`/studio/${colID}/${previousArtId}`); + } + }; + + // Navigate to next artifact + const navigateToNext = () => { + const { artifactIds, currentIndex, hasNext } = getNavigationInfo(); + + if (hasNext) { + setIsNavigating(true); + const nextArtId = artifactIds[currentIndex + 1]; + navigate(`/studio/${colID}/${nextArtId}`); + } + }; // Collection items fetching function const fetchCollection = async () => { @@ -144,6 +199,14 @@ function ArtefactEditor() { } }, [loaded]); + // Refetch metadata when artID changes (due to navigation) + useEffect(() => { + if (loaded && collection && isNavigating) { + fetchMetadata(); + setIsNavigating(false); + } + }, [artID, loaded, collection, isNavigating]); + useEffect(() => { if (collection && metadata) { const isInCollection = @@ -168,6 +231,8 @@ function ArtefactEditor() { return } + const { isFirst, isLast } = getNavigationInfo(); + return ( @@ -180,7 +245,13 @@ function ArtefactEditor() { - + @@ -198,7 +269,13 @@ function ArtefactEditor() { - + From 2d6645220ef224c80fd29e3a62bfc2d4ea0d4390 Mon Sep 17 00:00:00 2001 From: JunHam Date: Wed, 13 Aug 2025 23:57:49 +0800 Subject: [PATCH 04/21] Made metadataDisplay scrollable --- src/components/Catalogue/catalogueItemView.jsx | 6 ++---- src/components/Catalogue/metadataDisplay.jsx | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/Catalogue/catalogueItemView.jsx b/src/components/Catalogue/catalogueItemView.jsx index 60f08ab..8707164 100644 --- a/src/components/Catalogue/catalogueItemView.jsx +++ b/src/components/Catalogue/catalogueItemView.jsx @@ -1,4 +1,4 @@ -import { Portal, CloseButton, Image, Box, Text, Icon, Flex, useBreakpointValue } from "@chakra-ui/react"; +import { Portal, CloseButton, Image, Box, Text, Icon, Flex, Button, useBreakpointValue } from "@chakra-ui/react"; import { useEffect, useState, useRef } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { FaChevronLeft, FaChevronRight } from "react-icons/fa"; @@ -357,7 +357,6 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag > {item.title} - {title} - - + {selectedSegment === "metadata" ? ( Additional Info: - {metadata.addInfo} + {metadata.addInfo} )} {/* Figure headshots (if available) */} {Array.isArray(metadata.figureIDs) && metadata.figureIDs.length > 0 ? ( - + {metadata.figureIDs.map((id) => ( Date: Thu, 14 Aug 2025 00:49:19 +0800 Subject: [PATCH 05/21] Linked cb to ae --- .gitignore | 1 + .../Catalogue/catalogueItemView.jsx | 34 +++++++++++++++++-- src/components/Catalogue/itemViewMenu.jsx | 31 ----------------- src/components/Catalogue/section.jsx | 3 +- src/pages/Catalogue.jsx | 11 +++--- 5 files changed, 41 insertions(+), 39 deletions(-) delete mode 100644 src/components/Catalogue/itemViewMenu.jsx diff --git a/.gitignore b/.gitignore index 1461e83..7535d4a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ package-lock.json .env /src/pages/test.jsx +/src/components/Old \ No newline at end of file diff --git a/src/components/Catalogue/catalogueItemView.jsx b/src/components/Catalogue/catalogueItemView.jsx index 8707164..dfc3b6d 100644 --- a/src/components/Catalogue/catalogueItemView.jsx +++ b/src/components/Catalogue/catalogueItemView.jsx @@ -1,16 +1,18 @@ -import { Portal, CloseButton, Image, Box, Text, Icon, Flex, Button, useBreakpointValue } from "@chakra-ui/react"; +import { Portal, CloseButton, Image, Box, Text, Icon, Flex, useBreakpointValue } from "@chakra-ui/react"; +import { Tooltip } from "../../components/ui/tooltip" import { useEffect, useState, useRef } from "react"; +import { useNavigate } from "react-router-dom"; import { motion, AnimatePresence } from "framer-motion"; import { FaChevronLeft, FaChevronRight } from "react-icons/fa"; import ItemViewToggle from "./itemViewToggle"; -import ItemViewMenu from "./itemViewMenu"; import MetadataDisplay from "./metadataDisplay"; import ItemChat from "./itemChat"; +import { IoOpen } from "react-icons/io5"; const MotionBox = motion.create(Box); const MotionChevron = motion.create(Box); -const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imageSrc }) => { +const CatalogueItemView = ({ isOpen, onClose, title, sectionId, items, setDialogTitle, imageSrc }) => { const [isNavigating, setIsNavigating] = useState(false); const [direction, setDirection] = useState(0); const [isInitialRender, setIsInitialRender] = useState(true); @@ -20,6 +22,8 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag const scrollRef = useRef(null); const modalRef = useRef(null); const currentIndex = items.findIndex((item) => item.title === title); + const currentId = currentIndex !== -1 ? items[currentIndex].id : null; + const navigate = useNavigate() const prevItem = () => { if (!isNavigating && currentIndex > 0) { @@ -357,6 +361,18 @@ const CatalogueItemView = ({ isOpen, onClose, title, items, setDialogTitle, imag > {item.title} + + navigate()} + > + + {title} + + + navigate(`/studio/${sectionId}/${currentId}`)}/> + { - return ( - - - - - - - - - - - Open in Data Studio - - - Metadata Version History - - - - - - ); -}; - -export default ItemViewMenu; \ No newline at end of file diff --git a/src/components/Catalogue/section.jsx b/src/components/Catalogue/section.jsx index 5f781b6..cf9147d 100644 --- a/src/components/Catalogue/section.jsx +++ b/src/components/Catalogue/section.jsx @@ -5,7 +5,7 @@ import CatalogueItemView from "./catalogueItemView.jsx"; import ArrowOverlay from "./arrowOverlay.jsx"; import placeholderImage from "../../assets/placeholderImage.png" -const Section = ({ sectionTitle, onItemClick, artefacts = [] }) => { +const Section = ({ sectionTitle, sectionId, onItemClick, artefacts = [] }) => { const isMobile = useBreakpointValue({ base: true, md: false }); const items = artefacts.map((art) => ({ @@ -136,6 +136,7 @@ const Section = ({ sectionTitle, onItemClick, artefacts = [] }) => { isOpen={dialogOpen} onClose={() => setDialogOpen(false)} title={dialogTitle} + sectionId={sectionId} items={items} setDialogTitle={setDialogTitle} imageSrc={currentItem?.imageSrc} diff --git a/src/pages/Catalogue.jsx b/src/pages/Catalogue.jsx index 3dd990c..6519aba 100644 --- a/src/pages/Catalogue.jsx +++ b/src/pages/Catalogue.jsx @@ -19,6 +19,7 @@ function Catalogue() { async function fetchCatalogue() { try { const response = await server.get("/cdn/catalogue"); + console.log(response) if (response.data instanceof JSONResponse) { if (response.data.isErrorStatus()) { @@ -137,6 +138,7 @@ function Catalogue() {
@@ -145,11 +147,12 @@ function Catalogue() { {hasCategories && - Object.entries(categories).map(([groupName, artefacts]) => ( + Object.entries(categories).map(([catID, catObj]) => (
))} From 2e650a63030d2abda6c4e177abcd3bd78427e25e Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 01:16:49 +0800 Subject: [PATCH 06/21] Changed artifact to artefact --- src/pages/ArtefactEditor.jsx | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index 7d8bc9b..f198347 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -18,8 +18,8 @@ function ArtefactEditor() { const [isInvalid, setIsInvalid] = useState(false); const [isNavigating, setIsNavigating] = useState(false); - // Get the list of artifact IDs from collection data - const getArtifactIds = () => { + // Get the list of artefact IDs from collection data + const getartefactIds = () => { if (!collection) return []; // Handle array format (mmIDs) @@ -35,39 +35,45 @@ function ArtefactEditor() { return []; }; - // Get current artifact index and navigation info + // Get current artefact index and navigation info const getNavigationInfo = () => { - const artifactIds = getArtifactIds(); - const currentIndex = artifactIds.indexOf(artID); + const artefactIds = getartefactIds(); + const currentIndex = artefactIds.indexOf(artID); return { - artifactIds, + artefactIds, currentIndex, isFirst: currentIndex <= 0, - isLast: currentIndex >= artifactIds.length - 1, + isLast: currentIndex >= artefactIds.length - 1, hasPrevious: currentIndex > 0, - hasNext: currentIndex < artifactIds.length - 1 + hasNext: currentIndex < artefactIds.length - 1 }; }; - // Navigate to previous artifact + // Navigate to previous artefact const navigateToPrevious = () => { - const { artifactIds, currentIndex, hasPrevious } = getNavigationInfo(); + const { artefactIds, currentIndex, hasPrevious } = getNavigationInfo(); + + console.log(artefactIds) + console.log(currentIndex) if (hasPrevious) { setIsNavigating(true); - const previousArtId = artifactIds[currentIndex - 1]; + const previousArtId = artefactIds[currentIndex - 1]; navigate(`/studio/${colID}/${previousArtId}`); } }; - // Navigate to next artifact + // Navigate to next artefact const navigateToNext = () => { - const { artifactIds, currentIndex, hasNext } = getNavigationInfo(); + const { artefactIds, currentIndex, hasNext } = getNavigationInfo(); + + console.log(artefactIds) + console.log(currentIndex) if (hasNext) { setIsNavigating(true); - const nextArtId = artifactIds[currentIndex + 1]; + const nextArtId = artefactIds[currentIndex + 1]; navigate(`/studio/${colID}/${nextArtId}`); } }; From f6a38030be5b1dd4b0af9aefd31641e4e744dd80 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 06:49:17 +0800 Subject: [PATCH 07/21] Shifted unused compoenents to /old, added rough UI for group view --- src/components/Catalogue/cardItem.jsx | 1 + src/components/DataStudio/ItemGrid.jsx | 58 -------- src/components/DataStudio/ItemGroups.jsx | 72 ---------- src/main.jsx | 4 +- src/pages/CollectionView.jsx | 9 ++ src/pages/GroupView.jsx | 160 ++++++++++++++++++++++- 6 files changed, 169 insertions(+), 135 deletions(-) delete mode 100644 src/components/DataStudio/ItemGrid.jsx delete mode 100644 src/components/DataStudio/ItemGroups.jsx create mode 100644 src/pages/CollectionView.jsx diff --git a/src/components/Catalogue/cardItem.jsx b/src/components/Catalogue/cardItem.jsx index cb4426c..91a2279 100644 --- a/src/components/Catalogue/cardItem.jsx +++ b/src/components/Catalogue/cardItem.jsx @@ -6,6 +6,7 @@ import CardComponent from "./cardComponent"; const MotionBox = motion.create(Box); const CardItem = ({ itemTitle, itemDescription, imageSrc, expandable = true, descriptionDisplay = false }) => { + console.log(itemTitle, itemDescription, imageSrc) const isMobile = useBreakpointValue({ base: true, md: false }); const [isHovered, setIsHovered] = useState(false); diff --git a/src/components/DataStudio/ItemGrid.jsx b/src/components/DataStudio/ItemGrid.jsx deleted file mode 100644 index 8fcae2b..0000000 --- a/src/components/DataStudio/ItemGrid.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Box, Grid } from "@chakra-ui/react"; -import CardItem from "../Catalogue/cardItem.jsx"; -import placeholderImage from "../../assets/placeholderImage.png"; -import { useDraggable } from "@dnd-kit/core"; - -const dummyData = Array.from({ length: 24 }, (_, i) => ({ - id: `item-${i}`, - imageSrc: placeholderImage, - title: `Item ${i + 1}`, - description: `This is item ${i + 1}`, -})); - -function DraggableCard({ item }) { - const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ - id: item.id, - data: item, // Pass full item data for DragOverlay - }); - - return ( - - - - ); -} - -function ItemGrid() { - return ( - - - {dummyData.map((item) => ( - - ))} - - - ); -} - -export default ItemGrid; \ No newline at end of file diff --git a/src/components/DataStudio/ItemGroups.jsx b/src/components/DataStudio/ItemGroups.jsx deleted file mode 100644 index ae25348..0000000 --- a/src/components/DataStudio/ItemGroups.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; -import GroupToggle from "./groupToggle"; -import GroupCard from "./groupCard"; -import { useDroppable } from "@dnd-kit/core"; -import { useEffect, useState } from 'react' - -function DroppableGroupCard({ id, title, description, items }) { - const { setNodeRef, isOver } = useDroppable({ id }); - - return ( - - - - ); -} - -function ItemGroups({ droppedItems }) { - const [selectedGroup, setSelectedGroup] = useState("books"); - - const title = "Book of LIFE"; - const description = - "This book contains the life of Mr Joon (AKA B.A.S), a legend forged in caffeine, code, and sheer audacity."; - - return ( - - - - - - - {Array.from({ length: 10 }).map((_, i) => { - const groupId = `group-${i}`; - return ( - - ); - })} - - - ); -} - -export default ItemGroups; \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx index 5500b43..72b313c 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -21,13 +21,13 @@ import AnimateIn from './AnimateIn.jsx'; import DataImport from './pages/DataImport.jsx'; import PublicGallery from './pages/PublicGallery.jsx'; import PublicProfile from './pages/PublicProfile.jsx'; -import DataStudio from './pages/DataStudio.jsx'; import ArtefactEditor from './pages/ArtefactEditor.jsx'; import GroupView from './pages/GroupView.jsx'; import Profile from './pages/Profile.jsx'; import AdminConsole from './pages/AdminConsole.jsx'; import UserManagement from './pages/UserManagement.jsx'; import SuperuserLayout from './SuperuserLayout.jsx'; +import CollectionView from './pages/CollectionView.jsx'; const store = configureStore({ reducer: { @@ -60,7 +60,7 @@ createRoot(document.getElementById('root')).render( } /> - } /> + } /> } /> } /> diff --git a/src/pages/CollectionView.jsx b/src/pages/CollectionView.jsx new file mode 100644 index 0000000..7706f3a --- /dev/null +++ b/src/pages/CollectionView.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +function CollectionView() { + return ( +
CollectionView
+ ) +} + +export default CollectionView \ No newline at end of file diff --git a/src/pages/GroupView.jsx b/src/pages/GroupView.jsx index d3fbe4d..5ad3796 100644 --- a/src/pages/GroupView.jsx +++ b/src/pages/GroupView.jsx @@ -1,9 +1,163 @@ -import { useParams } from 'react-router-dom'; +import { Flex, Box, Text, Grid } from '@chakra-ui/react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { FaCircleArrowLeft } from 'react-icons/fa6'; +import { useEffect, useState } from 'react'; +import CentredSpinner from '../components/CentredSpinner'; +import server, { JSONResponse } from '../networking' +import ToastWizard from '../components/toastWizard'; +import CardItem from '../components/Catalogue/cardItem'; function GroupView() { const { colID } = useParams(); + const navigate = useNavigate(); + const [collection, setCollection] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - return
GroupView for collection {colID}
; + useEffect(() => { + const fetchCollection = async () => { + try { + setLoading(true); + const response = await server.get(`/cdn/collection/${colID}`); + console.log(response) + + if (response.data instanceof JSONResponse) { + if (response.data.isErrorStatus()) { + const errObject = { + response: { + data: response.data + } + }; + throw errObject; + } + + // Success case - format the data + let formattedData; + const apiData = response.data.raw.data; + + if (apiData.type === 'book') { + formattedData = { + type: 'book', + name: apiData.title, + description: apiData.subtitle || '', + items: apiData.mmArtefacts.map(art => ({ + id: art.id, + title: art.name, + description: art.description, + image: art.image || null + })) + }; + } else if (apiData.type === 'category') { + formattedData = { + type: 'category', + name: apiData.name, + description: apiData.description || '', + items: apiData.members.map(art => ({ + id: art.id, + title: art.name, + description: art.description, + image: art.image + })) + }; + } else if (apiData.type === 'batch') { + formattedData = { + type: 'batch', + name: apiData.name || `Batch ${apiData.id}`, + description: apiData.description || '', + items: apiData.artefacts.map(art => ({ + id: art.id, + title: art.name, + description: art.description, + image: art.image || null + })) + }; + } else { + throw new Error('Unknown collection type'); + } + + setCollection(formattedData); + // ToastWizard.standard("success", "Collection loaded", `${formattedData.name} loaded successfully`); + } else { + throw new Error("Unexpected response format"); + } + } catch (err) { + if (err.response && err.response.data instanceof JSONResponse) { + console.log("Error response in collection request:", err.response.data.fullMessage()); + setError(err.response.data.message); + + if (err.response.data.userErrorType()) { + // ToastWizard.standard("error", "Load failed", err.response.data.message); + } else { + // ToastWizard.ambiguousError(); + } + } else { + console.log("Unexpected error in collection request:", err); + setError(err.message || 'Failed to load collection'); + // ToastWizard.ambiguousError(); + } + } finally { + setLoading(false); + } + }; + + fetchCollection(); + }, [colID]); + + if (loading) return ; + if (error) return {error}; + if (!collection) return Collection not found; + + console.log(collection) + + return ( + + {/* Header with back button */} + + navigate(-1)} + size={40} + color="darkBlue" + /> + + {collection.name} + {collection.description && ( + + {collection.description} + + )} + + + + {/* Items grid */} + + {collection.items.map(item => ( + + ))} + + + {collection.items.length === 0 && ( + + This collection has no items + + )} + + ); } -export default GroupView; +export default GroupView; \ No newline at end of file From bea51026aa3387587bb36b82e366ad775e745aac Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 06:55:21 +0800 Subject: [PATCH 08/21] Updated AE fetchCollection to accept list from endpoint --- src/components/Catalogue/cardItem.jsx | 1 - src/pages/ArtefactEditor.jsx | 25 ++++++------------------- src/pages/Catalogue.jsx | 1 - 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/components/Catalogue/cardItem.jsx b/src/components/Catalogue/cardItem.jsx index 91a2279..cb4426c 100644 --- a/src/components/Catalogue/cardItem.jsx +++ b/src/components/Catalogue/cardItem.jsx @@ -6,7 +6,6 @@ import CardComponent from "./cardComponent"; const MotionBox = motion.create(Box); const CardItem = ({ itemTitle, itemDescription, imageSrc, expandable = true, descriptionDisplay = false }) => { - console.log(itemTitle, itemDescription, imageSrc) const isMobile = useBreakpointValue({ base: true, md: false }); const [isHovered, setIsHovered] = useState(false); diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index f198347..621bbce 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -19,27 +19,16 @@ function ArtefactEditor() { const [isNavigating, setIsNavigating] = useState(false); // Get the list of artefact IDs from collection data - const getartefactIds = () => { - if (!collection) return []; - - // Handle array format (mmIDs) - if (Array.isArray(collection.mmIDs)) { - return collection.mmIDs; - } - - // Handle object format (members) - if (collection.members && typeof collection.members === 'object') { - return Object.keys(collection.members); - } - - return []; + const getArtefactIds = () => { + // collection is now always an array of IDs + return Array.isArray(collection) ? collection : []; }; // Get current artefact index and navigation info const getNavigationInfo = () => { - const artefactIds = getartefactIds(); + const artefactIds = getArtefactIds(); const currentIndex = artefactIds.indexOf(artID); - + return { artefactIds, currentIndex, @@ -215,9 +204,7 @@ function ArtefactEditor() { useEffect(() => { if (collection && metadata) { - const isInCollection = - (Array.isArray(collection.mmIDs) && collection.mmIDs.includes(artID)) || - (collection.members && Object.keys(collection.members).includes(artID)); + const isInCollection = Array.isArray(collection) && collection.includes(artID); if (!isInCollection) { setIsInvalid(true); diff --git a/src/pages/Catalogue.jsx b/src/pages/Catalogue.jsx index 6519aba..b406cdf 100644 --- a/src/pages/Catalogue.jsx +++ b/src/pages/Catalogue.jsx @@ -19,7 +19,6 @@ function Catalogue() { async function fetchCatalogue() { try { const response = await server.get("/cdn/catalogue"); - console.log(response) if (response.data instanceof JSONResponse) { if (response.data.isErrorStatus()) { From 01eb7ae962edc7b7408321dff21534dfdde31652 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:03:08 +0800 Subject: [PATCH 09/21] Fixed AE refetching data --- src/pages/ArtefactEditor.jsx | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index 621bbce..d861267 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -28,6 +28,9 @@ function ArtefactEditor() { const getNavigationInfo = () => { const artefactIds = getArtefactIds(); const currentIndex = artefactIds.indexOf(artID); + + console.log(artefactIds) + console.log(currentIndex) return { artefactIds, @@ -39,31 +42,19 @@ function ArtefactEditor() { }; }; - // Navigate to previous artefact const navigateToPrevious = () => { const { artefactIds, currentIndex, hasPrevious } = getNavigationInfo(); - - console.log(artefactIds) - console.log(currentIndex) - if (hasPrevious) { setIsNavigating(true); - const previousArtId = artefactIds[currentIndex - 1]; - navigate(`/studio/${colID}/${previousArtId}`); + navigate(`/studio/${colID}/${artefactIds[currentIndex - 1]}`); } }; - // Navigate to next artefact const navigateToNext = () => { const { artefactIds, currentIndex, hasNext } = getNavigationInfo(); - - console.log(artefactIds) - console.log(currentIndex) - if (hasNext) { setIsNavigating(true); - const nextArtId = artefactIds[currentIndex + 1]; - navigate(`/studio/${colID}/${nextArtId}`); + navigate(`/studio/${colID}/${artefactIds[currentIndex + 1]}`); } }; @@ -186,21 +177,20 @@ function ArtefactEditor() { } }; - // Fetch metadata if user is loaded + // Fetch collection once after load useEffect(() => { if (loaded) { - fetchCollection() - fetchMetadata() + fetchCollection(); } }, [loaded]); - // Refetch metadata when artID changes (due to navigation) + // Always fetch metadata when artID changes useEffect(() => { - if (loaded && collection && isNavigating) { + if (loaded && artID) { fetchMetadata(); - setIsNavigating(false); + setIsNavigating(false); // reset navigating state } - }, [artID, loaded, collection, isNavigating]); + }, [artID, loaded]); useEffect(() => { if (collection && metadata) { From 42ae28f7022f661233579fd0e19e38a29faab52b Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:06:20 +0800 Subject: [PATCH 10/21] Fixed back button for AE --- src/pages/ArtefactEditor.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index d861267..4818cb8 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -28,9 +28,6 @@ function ArtefactEditor() { const getNavigationInfo = () => { const artefactIds = getArtefactIds(); const currentIndex = artefactIds.indexOf(artID); - - console.log(artefactIds) - console.log(currentIndex) return { artefactIds, @@ -46,7 +43,7 @@ function ArtefactEditor() { const { artefactIds, currentIndex, hasPrevious } = getNavigationInfo(); if (hasPrevious) { setIsNavigating(true); - navigate(`/studio/${colID}/${artefactIds[currentIndex - 1]}`); + navigate(`/studio/${colID}/${artefactIds[currentIndex - 1]}`, { replace: true }); } }; @@ -54,7 +51,7 @@ function ArtefactEditor() { const { artefactIds, currentIndex, hasNext } = getNavigationInfo(); if (hasNext) { setIsNavigating(true); - navigate(`/studio/${colID}/${artefactIds[currentIndex + 1]}`); + navigate(`/studio/${colID}/${artefactIds[currentIndex + 1]}`, { replace: true }); } }; From a6f04302afb91af44528d64a3d980897b608c787 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:19:01 +0800 Subject: [PATCH 11/21] Added navigation from section to group view --- src/components/Catalogue/section.jsx | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/components/Catalogue/section.jsx b/src/components/Catalogue/section.jsx index cf9147d..26cc8ab 100644 --- a/src/components/Catalogue/section.jsx +++ b/src/components/Catalogue/section.jsx @@ -1,12 +1,14 @@ -import { Box, Text, Flex, useBreakpointValue, Image } from "@chakra-ui/react"; +import { Box, Text, Flex, useBreakpointValue, Image, Button } from "@chakra-ui/react"; import { useRef, useState, useEffect } from "react"; import CardItem from "./cardItem.jsx"; import CatalogueItemView from "./catalogueItemView.jsx"; import ArrowOverlay from "./arrowOverlay.jsx"; import placeholderImage from "../../assets/placeholderImage.png" +import { useNavigate } from "react-router-dom"; const Section = ({ sectionTitle, sectionId, onItemClick, artefacts = [] }) => { const isMobile = useBreakpointValue({ base: true, md: false }); + const navigate = useNavigate() const items = artefacts.map((art) => ({ id: art.id, @@ -66,15 +68,20 @@ const Section = ({ sectionTitle, sectionId, onItemClick, artefacts = [] }) => { return ( - - {sectionTitle} - + + + {sectionTitle} + + + + {!isMobile && ( <> From ab5912fbd2921a520f938734f4c0fad92eb88096 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:40:37 +0800 Subject: [PATCH 12/21] Added smaller component groupCardItem for GroupView --- src/components/DataStudio/groupCardItem.jsx | 25 ++++++++++++++ src/pages/GroupView.jsx | 38 +++++++++++---------- 2 files changed, 45 insertions(+), 18 deletions(-) create mode 100644 src/components/DataStudio/groupCardItem.jsx diff --git a/src/components/DataStudio/groupCardItem.jsx b/src/components/DataStudio/groupCardItem.jsx new file mode 100644 index 0000000..b7315e2 --- /dev/null +++ b/src/components/DataStudio/groupCardItem.jsx @@ -0,0 +1,25 @@ +import { Box } from "@chakra-ui/react"; +import CardComponent from "../Catalogue/cardComponent"; + +const GroupCardItem = ({ itemTitle, itemDescription, imageSrc }) => { + + return ( + <> + {/* Base Card Container */} + + + + + ); +}; + +export default GroupCardItem; \ No newline at end of file diff --git a/src/pages/GroupView.jsx b/src/pages/GroupView.jsx index 5ad3796..af303d8 100644 --- a/src/pages/GroupView.jsx +++ b/src/pages/GroupView.jsx @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'; import CentredSpinner from '../components/CentredSpinner'; import server, { JSONResponse } from '../networking' import ToastWizard from '../components/toastWizard'; -import CardItem from '../components/Catalogue/cardItem'; +import GroupCardItem from '../components/DataStudio/groupCardItem'; function GroupView() { const { colID } = useParams(); @@ -107,8 +107,6 @@ function GroupView() { if (error) return {error}; if (!collection) return Collection not found; - console.log(collection) - return ( {/* Header with back button */} @@ -120,15 +118,19 @@ function GroupView() { color="darkBlue" /> - {collection.name} - {collection.description && ( - - {collection.description} - - )} + Group View + + {collection.name} + {collection.description && ( + + {collection.description} + + )} + + {/* Items grid */} {collection.items.map(item => ( - + <> + + ))} From f3b7d7c9d4045ad5590c6303daea18519d97669b Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:42:02 +0800 Subject: [PATCH 13/21] Removed debug console log --- src/pages/GroupView.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/GroupView.jsx b/src/pages/GroupView.jsx index af303d8..c652d53 100644 --- a/src/pages/GroupView.jsx +++ b/src/pages/GroupView.jsx @@ -19,7 +19,6 @@ function GroupView() { try { setLoading(true); const response = await server.get(`/cdn/collection/${colID}`); - console.log(response) if (response.data instanceof JSONResponse) { if (response.data.isErrorStatus()) { From fa6d5c79f1d085de268b19c158593f77189be635 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 07:45:04 +0800 Subject: [PATCH 14/21] Shifted DataStudio to Old --- src/pages/DataStudio.jsx | 83 ---------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 src/pages/DataStudio.jsx diff --git a/src/pages/DataStudio.jsx b/src/pages/DataStudio.jsx deleted file mode 100644 index 5efb649..0000000 --- a/src/pages/DataStudio.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import { DndContext, DragOverlay } from "@dnd-kit/core"; -import { useState } from "react"; -import { Box, Flex, Text } from "@chakra-ui/react"; -import ItemGrid from "../components/DataStudio/ItemGrid.jsx"; -import ItemGroups from "../components/DataStudio/ItemGroups.jsx"; -import CardItem from "../components/Catalogue/cardItem.jsx"; - -function DataStudio() { - const [droppedItems, setDroppedItems] = useState({}); - const [activeItem, setActiveItem] = useState(null); - - const handleDragStart = (event) => { - setActiveItem(event.active.data.current); - }; - - const handleDragEnd = (event) => { - const { active, over } = event; - setActiveItem(null); - - if (over && active) { - const groupId = over.id; - const itemId = active.id; - - setDroppedItems((prev) => { - // Avoid duplicates by checking if item already exists in the group - const existingItems = prev[groupId] || []; - if (existingItems.some((item) => item.id === itemId)) { - return prev; - } - - return { - ...prev, - [groupId]: [...existingItems, active.data.current], - }; - }); - } - }; - - return ( - - - {/* Left Panel (Draggable Items) */} - - - Data Studio - Batch - - - - - - - {/* Right Panel (Droppable Groups) */} - - - - - - {/* Drag Preview */} - - {activeItem ? ( - - - - ) : null} - - - ); -} - -export default DataStudio; \ No newline at end of file From bae85ae3bfa1c2fb7200099519671438a76d1cd6 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 08:19:19 +0800 Subject: [PATCH 15/21] Improved responsiveness for AE --- src/components/Catalogue/section.jsx | 4 +- src/components/DataStudio/editorCard.jsx | 28 +++-- src/components/DataStudio/metadataToggle.jsx | 18 ++- src/pages/ArtefactEditor.jsx | 113 +++++++++++++------ 4 files changed, 113 insertions(+), 50 deletions(-) diff --git a/src/components/Catalogue/section.jsx b/src/components/Catalogue/section.jsx index 26cc8ab..0d9bb91 100644 --- a/src/components/Catalogue/section.jsx +++ b/src/components/Catalogue/section.jsx @@ -5,6 +5,7 @@ import CatalogueItemView from "./catalogueItemView.jsx"; import ArrowOverlay from "./arrowOverlay.jsx"; import placeholderImage from "../../assets/placeholderImage.png" import { useNavigate } from "react-router-dom"; +import { BsEye } from "react-icons/bs"; const Section = ({ sectionTitle, sectionId, onItemClick, artefacts = [] }) => { const isMobile = useBreakpointValue({ base: true, md: false }); @@ -79,7 +80,8 @@ const Section = ({ sectionTitle, sectionId, onItemClick, artefacts = [] }) => { diff --git a/src/components/DataStudio/editorCard.jsx b/src/components/DataStudio/editorCard.jsx index 29dbc71..0b1e50b 100644 --- a/src/components/DataStudio/editorCard.jsx +++ b/src/components/DataStudio/editorCard.jsx @@ -1,4 +1,4 @@ -import { Card, Button, Flex, Text, Field, Input, Textarea, Box } from "@chakra-ui/react"; +import { Card, Button, Flex, Text, Field, Input, Textarea, Box, useBreakpointValue } from "@chakra-ui/react"; import { useState, useEffect, useRef } from "react"; import { IoInformationCircleOutline } from "react-icons/io5"; import { MdOutlineEdit, MdOutlineCancel } from "react-icons/md"; @@ -96,6 +96,9 @@ function EditorCard({ metadata, artefactId, refreshArtefactData }) { const [originalArtefactData, setOriginalArtefactData] = useState({}); const [artefactData, setArtefactData] = useState({}); + // Responsive layout + const isMobile = useBreakpointValue({ base: true, md: false }); + // Initialize data when metadata prop changes useEffect(() => { if (metadata) { @@ -155,16 +158,16 @@ function EditorCard({ metadata, artefactId, refreshArtefactData }) { return ( <> - - + + Artefact Details - - - @@ -174,8 +177,8 @@ function EditorCard({ metadata, artefactId, refreshArtefactData }) { {isMMArtefact ? ( <> - - Name: + + Name: {isEditing ? ( {/* MM Artefact Specific Fields */} - - Transcription: + + Transcription: @@ -248,8 +252,8 @@ function EditorCard({ metadata, artefactId, refreshArtefactData }) { ) : ( - - Name: + + Name: {isEditing ? ( { +const MetadataToggle = ({ value, onChange, isMobile }) => { const items = [ { value: "tradCN", label: "Trad CN" }, { value: "simplifiedCN", label: "Simp CN" }, @@ -8,13 +8,18 @@ const MetadataToggle = ({ value, onChange }) => { { value: "summary", label: "SUM" }, ]; + // Responsive sizing + const segmentSize = useBreakpointValue({ base: "sm", md: "md" }); + const fontSize = useBreakpointValue({ base: "xs", md: "sm" }); + const padding = useBreakpointValue({ base: "0.5", md: "1" }); + return ( onChange(value)} - size="sm" + size={segmentSize} bg="gray.100" - p="1" + p={padding} rounded="lg" boxShadow="sm" w="100%" @@ -24,7 +29,7 @@ const MetadataToggle = ({ value, onChange }) => { { value: item.value, label: ( {item.label} @@ -50,6 +57,7 @@ const MetadataToggle = ({ value, onChange }) => { display: "flex", justifyContent: "center", alignItems: "center", + padding: isMobile ? "0.25rem" : "0.5rem", }, }))} /> diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index 4818cb8..aef3996 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -1,4 +1,4 @@ -import { Box, Flex, Text, Image } from "@chakra-ui/react"; +import { Box, Flex, Text, Image, useBreakpointValue } from "@chakra-ui/react"; import { useParams, useNavigate } from 'react-router-dom'; import { useEffect, useRef, useState } from "react"; import { useSelector } from "react-redux"; @@ -18,6 +18,14 @@ function ArtefactEditor() { const [isInvalid, setIsInvalid] = useState(false); const [isNavigating, setIsNavigating] = useState(false); + // Responsive layout values + const isMobile = useBreakpointValue({ base: true, md: false }); + const containerHeight = useBreakpointValue({ base: "auto", md: "80vh" }); + const contentHeight = useBreakpointValue({ base: "auto", md: "calc(79vh - 45px)" }); + const imageWidth = useBreakpointValue({ base: "100%", md: "46%" }); + const editorWidth = useBreakpointValue({ base: "100%", md: "46%" }); + const chevronWidth = useBreakpointValue({ base: "8%", md: "4%" }); + // Get the list of artefact IDs from collection data const getArtefactIds = () => { // collection is now always an array of IDs @@ -214,7 +222,7 @@ function ArtefactEditor() { const { isFirst, isLast } = getNavigationInfo(); return ( - + navigate(-1)} size={40} color='darkBlue' /> @@ -223,41 +231,82 @@ function ArtefactEditor() { - - - + {isMobile ? ( + + + + + + + + + + + + + + + + + + + ) : ( + + + + - - - + + + - - - + + + - - + + + - + )} ); } From a4623d7c0d20a008d805af04edb7d5e54d232920 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 08:21:30 +0800 Subject: [PATCH 16/21] Added navigatiuon for catalogue item view for mobile --- src/components/Catalogue/catalogueItemView.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Catalogue/catalogueItemView.jsx b/src/components/Catalogue/catalogueItemView.jsx index dfc3b6d..853899e 100644 --- a/src/components/Catalogue/catalogueItemView.jsx +++ b/src/components/Catalogue/catalogueItemView.jsx @@ -369,9 +369,8 @@ const CatalogueItemView = ({ isOpen, onClose, title, sectionId, items, setDialog closeDelay={150} openDelay={150} contentProps={{ css: { "--tooltip-bg": "#12144C" } }} - onClick={() => navigate()} > - + navigate(`/studio/${sectionId}/${currentId}`)}/> From 1d6daa5330e347c4b124575034b90798876b6c11 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 09:26:28 +0800 Subject: [PATCH 17/21] Removed collection view --- src/main.jsx | 2 -- src/pages/CollectionView.jsx | 9 --------- 2 files changed, 11 deletions(-) delete mode 100644 src/pages/CollectionView.jsx diff --git a/src/main.jsx b/src/main.jsx index 72b313c..4f79425 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -27,7 +27,6 @@ import Profile from './pages/Profile.jsx'; import AdminConsole from './pages/AdminConsole.jsx'; import UserManagement from './pages/UserManagement.jsx'; import SuperuserLayout from './SuperuserLayout.jsx'; -import CollectionView from './pages/CollectionView.jsx'; const store = configureStore({ reducer: { @@ -60,7 +59,6 @@ createRoot(document.getElementById('root')).render( } /> - } /> } /> } /> diff --git a/src/pages/CollectionView.jsx b/src/pages/CollectionView.jsx deleted file mode 100644 index 7706f3a..0000000 --- a/src/pages/CollectionView.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -function CollectionView() { - return ( -
CollectionView
- ) -} - -export default CollectionView \ No newline at end of file From d99057492d9afd417ee8bb2c6d0dc35f6e778109 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 09:28:24 +0800 Subject: [PATCH 18/21] Shifted unused components to Old folder --- src/components/DataStudio/groupCard.jsx | 24 ---- .../DataStudio/groupItemsSection.jsx | 105 ------------------ src/components/DataStudio/groupToggle.jsx | 58 ---------- 3 files changed, 187 deletions(-) delete mode 100644 src/components/DataStudio/groupCard.jsx delete mode 100644 src/components/DataStudio/groupItemsSection.jsx delete mode 100644 src/components/DataStudio/groupToggle.jsx diff --git a/src/components/DataStudio/groupCard.jsx b/src/components/DataStudio/groupCard.jsx deleted file mode 100644 index 51f5b0e..0000000 --- a/src/components/DataStudio/groupCard.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Card } from "@chakra-ui/react"; -import GroupItemsSection from "./groupItemsSection"; - -function GroupCard({ title, description }) { - const truncatedDesc = description.length > 50 ? description.slice(0, 50) + "..." : description; - - return ( - - - - {title} - - - {truncatedDesc} - - - - - - - ); -} - -export default GroupCard; \ No newline at end of file diff --git a/src/components/DataStudio/groupItemsSection.jsx b/src/components/DataStudio/groupItemsSection.jsx deleted file mode 100644 index 6643368..0000000 --- a/src/components/DataStudio/groupItemsSection.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import { Box, Image, Flex } from "@chakra-ui/react"; -import { useRef, useState, useEffect } from "react"; -import ArrowOverlay from "../Catalogue/arrowOverlay"; -import placeholderImage from "../../assets/placeholderImage.png"; - -function GroupItemsSection() { - const scrollRef = useRef(null); - const [atStart, setAtStart] = useState(true); - const [atEnd, setAtEnd] = useState(false); - const [isOverflowing, setIsOverflowing] = useState(false); - - const items = Array.from({ length: 12 }, (_, i) => ({ - id: i + 1, - imageSrc: placeholderImage, - name: `Item ${i + 1}`, - })); - - const checkScrollEdges = () => { - const node = scrollRef.current; - if (!node) return; - - setAtStart(node.scrollLeft === 0); - setAtEnd( - Math.ceil(node.scrollLeft + node.clientWidth) >= node.scrollWidth - ); - - setIsOverflowing(node.scrollWidth > node.clientWidth); - }; - - const scroll = (direction) => { - if (!scrollRef.current) return; - const scrollAmount = 300; - scrollRef.current.scrollBy({ - left: direction === "left" ? -scrollAmount : scrollAmount, - behavior: "smooth", - }); - }; - - useEffect(() => { - const node = scrollRef.current; - if (!node) return; - - checkScrollEdges(); - node.addEventListener("scroll", checkScrollEdges); - window.addEventListener("resize", checkScrollEdges); - - return () => { - node.removeEventListener("scroll", checkScrollEdges); - window.removeEventListener("resize", checkScrollEdges); - }; - }, [items]); - - return ( - - {/* Arrow overlays with small size */} - scroll("left")} - isOverflowing={isOverflowing && !atStart} - smaller={true} - /> - scroll("right")} - isOverflowing={isOverflowing && !atEnd} - smaller={true} - /> - - {/* Scrollable items container */} - - {items.map((item) => ( - - {item.name} - - ))} - - - ); -} - -export default GroupItemsSection; diff --git a/src/components/DataStudio/groupToggle.jsx b/src/components/DataStudio/groupToggle.jsx deleted file mode 100644 index 9cd9a88..0000000 --- a/src/components/DataStudio/groupToggle.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { HStack, SegmentGroup, Text } from "@chakra-ui/react"; -import { FaBookOpen, FaImages, FaCubes } from "react-icons/fa"; - -const GroupToggle = ({ value, onChange }) => { - const items = [ - { - value: "books", - label: ( - - - - Books - - - ), - }, - { - value: "categories", - label: ( - - - - Categories - - - ), - }, - { - value: "batch", - label: ( - - - - Batch - - - ), - }, - ]; - - return ( - onChange(value)} - size="lg" - bg="gray.50" - p="1" - rounded="l" - boxShadow="md" - gap="1" - > - - - - ); -}; - -export default GroupToggle; From 256ce43b76c8deac3a969026d48f4afa32c89e67 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 09:35:22 +0800 Subject: [PATCH 19/21] Added cursor pointer for IoOpen --- src/components/Catalogue/catalogueItemView.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Catalogue/catalogueItemView.jsx b/src/components/Catalogue/catalogueItemView.jsx index 853899e..2afa607 100644 --- a/src/components/Catalogue/catalogueItemView.jsx +++ b/src/components/Catalogue/catalogueItemView.jsx @@ -370,7 +370,7 @@ const CatalogueItemView = ({ isOpen, onClose, title, sectionId, items, setDialog openDelay={150} contentProps={{ css: { "--tooltip-bg": "#12144C" } }} > - navigate(`/studio/${sectionId}/${currentId}`)}/> + navigate(`/studio/${sectionId}/${currentId}`)} cursor={"pointer"}/>
@@ -508,7 +508,7 @@ const CatalogueItemView = ({ isOpen, onClose, title, sectionId, items, setDialog openDelay={150} contentProps={{ css: { "--tooltip-bg": "#12144C" } }} > - navigate(`/studio/${sectionId}/${currentId}`)}/> + navigate(`/studio/${sectionId}/${currentId}`)} cursor={"pointer"}/>
From 6e4fafefdbc8914ab3b280d168cc4ef93aa660d7 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 10:08:49 +0800 Subject: [PATCH 20/21] Added toast wizards for groupview fetch collection --- src/pages/GroupView.jsx | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/pages/GroupView.jsx b/src/pages/GroupView.jsx index c652d53..69672f6 100644 --- a/src/pages/GroupView.jsx +++ b/src/pages/GroupView.jsx @@ -75,7 +75,6 @@ function GroupView() { } setCollection(formattedData); - // ToastWizard.standard("success", "Collection loaded", `${formattedData.name} loaded successfully`); } else { throw new Error("Unexpected response format"); } @@ -85,14 +84,38 @@ function GroupView() { setError(err.response.data.message); if (err.response.data.userErrorType()) { - // ToastWizard.standard("error", "Load failed", err.response.data.message); + ToastWizard.standard( + "error", + "An Error Occured", + "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); } else { - // ToastWizard.ambiguousError(); + ToastWizard.standard( + "error", + "An Error Occured", + "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); } } else { console.log("Unexpected error in collection request:", err); setError(err.message || 'Failed to load collection'); - // ToastWizard.ambiguousError(); + ToastWizard.standard( + "error", + "An Error Occured", + "We could not fetch the collection data. Please try again later.", + 3000, + true, + fetchCollection, + 'Retry' + ); } } finally { setLoading(false); @@ -102,9 +125,7 @@ function GroupView() { fetchCollection(); }, [colID]); - if (loading) return ; - if (error) return {error}; - if (!collection) return Collection not found; + if (loading || !collection || error) return ; return ( @@ -141,14 +162,12 @@ function GroupView() { gap={10} > {collection.items.map(item => ( - <> - - + ))} From 0e25c0c76f9e3fd60d730243cc4c1e042f9caec8 Mon Sep 17 00:00:00 2001 From: JunHam Date: Thu, 14 Aug 2025 11:03:19 +0800 Subject: [PATCH 21/21] Removed unused states, Fixed responsiveness for AE --- src/pages/ArtefactEditor.jsx | 16 +++++----------- src/pages/GroupView.jsx | 5 +---- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/pages/ArtefactEditor.jsx b/src/pages/ArtefactEditor.jsx index aef3996..c101e17 100644 --- a/src/pages/ArtefactEditor.jsx +++ b/src/pages/ArtefactEditor.jsx @@ -1,6 +1,6 @@ import { Box, Flex, Text, Image, useBreakpointValue } from "@chakra-ui/react"; import { useParams, useNavigate } from 'react-router-dom'; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { useSelector } from "react-redux"; import ToastWizard from "../components/toastWizard"; import server, { JSONResponse } from "../networking"; @@ -16,12 +16,9 @@ function ArtefactEditor() { const { loaded } = useSelector(state => state.auth); const navigate = useNavigate(); const [isInvalid, setIsInvalid] = useState(false); - const [isNavigating, setIsNavigating] = useState(false); // Responsive layout values const isMobile = useBreakpointValue({ base: true, md: false }); - const containerHeight = useBreakpointValue({ base: "auto", md: "80vh" }); - const contentHeight = useBreakpointValue({ base: "auto", md: "calc(79vh - 45px)" }); const imageWidth = useBreakpointValue({ base: "100%", md: "46%" }); const editorWidth = useBreakpointValue({ base: "100%", md: "46%" }); const chevronWidth = useBreakpointValue({ base: "8%", md: "4%" }); @@ -50,7 +47,6 @@ function ArtefactEditor() { const navigateToPrevious = () => { const { artefactIds, currentIndex, hasPrevious } = getNavigationInfo(); if (hasPrevious) { - setIsNavigating(true); navigate(`/studio/${colID}/${artefactIds[currentIndex - 1]}`, { replace: true }); } }; @@ -58,7 +54,6 @@ function ArtefactEditor() { const navigateToNext = () => { const { artefactIds, currentIndex, hasNext } = getNavigationInfo(); if (hasNext) { - setIsNavigating(true); navigate(`/studio/${colID}/${artefactIds[currentIndex + 1]}`, { replace: true }); } }; @@ -187,13 +182,12 @@ function ArtefactEditor() { if (loaded) { fetchCollection(); } - }, [loaded]); + }, [loaded, colID]); // Always fetch metadata when artID changes useEffect(() => { if (loaded && artID) { fetchMetadata(); - setIsNavigating(false); // reset navigating state } }, [artID, loaded]); @@ -222,7 +216,7 @@ function ArtefactEditor() { const { isFirst, isLast } = getNavigationInfo(); return ( - + navigate(-1)} size={40} color='darkBlue' /> @@ -232,7 +226,7 @@ function ArtefactEditor() { {isMobile ? ( - + ) : ( - + { const fetchCollection = async () => { @@ -81,7 +80,6 @@ function GroupView() { } catch (err) { if (err.response && err.response.data instanceof JSONResponse) { console.log("Error response in collection request:", err.response.data.fullMessage()); - setError(err.response.data.message); if (err.response.data.userErrorType()) { ToastWizard.standard( @@ -106,7 +104,6 @@ function GroupView() { } } else { console.log("Unexpected error in collection request:", err); - setError(err.message || 'Failed to load collection'); ToastWizard.standard( "error", "An Error Occured", @@ -125,7 +122,7 @@ function GroupView() { fetchCollection(); }, [colID]); - if (loading || !collection || error) return ; + if (loading || !collection ) return ; return (