@@ -10,10 +10,8 @@ import CardFilter from "@/components/Yugioh/CardFilter";
1010import FilterPanel from "@/components/Yugioh/FilterPanel" ;
1111import YugiohPagination from "@/components/Yugioh/YugiohPagination" ;
1212import { dispatchAuthStateChange } from "@/utils/authState" ;
13- import clientPromise from "@/utils/mongo.js" ;
1413import jwt from "jsonwebtoken" ;
1514import { getTokenFromRequest } from "@/middleware/authenticate" ;
16- import { ensureSafeUserId } from "@/utils/securityValidators.js" ;
1715
1816const TableView = dynamic ( ( ) => import ( "@/components/Yugioh/TableView" ) , {
1917 ssr : false ,
@@ -37,13 +35,13 @@ const ITEMS_PER_PAGE = 12;
3735const DEFAULT_FILTERS = { rarity : [ ] , condition : [ ] , printing : [ ] } ;
3836const DEFAULT_SORT = { key : "number" , direction : "ascending" } ;
3937
40- const MyCollection = ( { initialCards = [ ] , initialAuthState = false } ) => {
38+ const MyCollection = ( { initialAuthState = false } ) => {
4139 const router = useRouter ( ) ;
4240 const [ notification , setNotification ] = useState ( { show : false , message : '' } ) ;
43- const [ cards , setCards ] = useState ( ( ) => ( Array . isArray ( initialCards ) ? initialCards : [ ] ) ) ;
41+ const [ cards , setCards ] = useState ( [ ] ) ;
4442 const [ viewMode , setViewMode ] = useState ( "grid" ) ;
4543 const [ isAuthenticated , setIsAuthenticated ] = useState ( ( ) => Boolean ( initialAuthState ) ) ;
46- const [ isLoading , setIsLoading ] = useState ( ( ) => ! initialAuthState ) ;
44+ const [ isLoading , setIsLoading ] = useState ( true ) ;
4745 const [ isUpdatingPrices , setIsUpdatingPrices ] = useState ( false ) ;
4846 const [ searchValue , setSearchValue ] = useState ( "" ) ;
4947 const [ filters , setFilters ] = useState ( ( ) => ( { ...DEFAULT_FILTERS } ) ) ;
@@ -69,14 +67,6 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
6967 } , [ ] ) ;
7068
7169 useEffect ( ( ) => {
72- if ( initialAuthState ) {
73- setIsAuthenticated ( true ) ;
74- setCards ( Array . isArray ( initialCards ) ? initialCards : [ ] ) ;
75- setIsLoading ( false ) ;
76- dispatchAuthStateChange ( true ) ;
77- return ;
78- }
79-
8070 let isActive = true ;
8171
8272 const initialize = async ( ) => {
@@ -88,20 +78,26 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
8878 return ;
8979 }
9080
91- setIsAuthenticated ( true ) ;
9281 setCards ( data ) ;
82+ setIsAuthenticated ( true ) ;
9383 dispatchAuthStateChange ( true ) ;
9484 } catch ( error ) {
95- if ( isActive ) {
96- console . error ( "Error loading collection:" , error ) ;
97- if ( error ?. status === 401 ) {
98- setIsAuthenticated ( false ) ;
99- setCards ( [ ] ) ;
100- dispatchAuthStateChange ( false ) ;
101- } else {
102- setIsAuthenticated ( true ) ;
103- dispatchAuthStateChange ( true ) ;
104- }
85+ if ( ! isActive ) {
86+ return ;
87+ }
88+
89+ console . error ( "Error loading collection:" , error ) ;
90+ if ( error ?. status === 401 ) {
91+ setIsAuthenticated ( false ) ;
92+ setCards ( [ ] ) ;
93+ dispatchAuthStateChange ( false ) ;
94+ } else {
95+ setIsAuthenticated ( true ) ;
96+ setNotification ( ( prev ) => ( {
97+ ...prev ,
98+ show : true ,
99+ message : "Failed to load your collection. Please try again." ,
100+ } ) ) ;
105101 }
106102 } finally {
107103 if ( isActive ) {
@@ -115,7 +111,7 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
115111 return ( ) => {
116112 isActive = false ;
117113 } ;
118- } , [ fetchCards , initialAuthState , initialCards ] ) ;
114+ } , [ fetchCards ] ) ;
119115
120116 const refreshCollection = useCallback ( async ( ) => {
121117 try {
@@ -531,25 +527,9 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
531527 < main
532528 className = { `mx-auto w-full px-4 pb-20 pt-10 sm:px-6 lg:px-8 ${ isDesktopFilterOpen ? "lg:pr-80" : "" } ` }
533529 >
534- < div className = "hidden pb-4 lg:flex lg:justify-end" >
535- < button
536- type = "button"
537- onClick = { toggleDesktopFilters }
538- aria-expanded = { isDesktopFilterOpen }
539- aria-controls = "desktop-filter-panel"
540- className = "inline-flex items-center gap-2 rounded-full border border-white/20 bg-white/10 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/40"
541- >
542- < Filter size = { 16 } />
543- { isDesktopFilterOpen ? "Hide Filters" : "Show Filters" }
544- { activeFilterBadges . length > 0 && (
545- < span className = "ml-2 rounded-full bg-indigo-500/40 px-2 py-0.5 text-xs font-semibold text-indigo-50" >
546- { activeFilterBadges . length }
547- </ span >
548- ) }
549- </ button >
550- </ div >
551- < header className = "rounded-3xl border border-white/10 bg-black/40 p-8 shadow-2xl" >
552- < div className = "flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between" >
530+
531+ < header className = "rounded-xl border border-white/10 bg-black/40 p-8 shadow-2xl" >
532+ < div className = "flex flex-wrap flex-col lg:flex-row lg:items-end lg:justify-between" >
553533 < div className = "text-center lg:text-left" >
554534 < p className = "text-xs font-semibold uppercase tracking-[0.35em] text-white/50" > Collection</ p >
555535 < h1 className = "mt-4 text-3xl font-bold md:text-4xl" > My Yu-Gi-Oh! Collection</ h1 >
@@ -558,17 +538,17 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
558538 </ p >
559539 </ div >
560540 { hasCards && (
561- < div className = "grid gap-4 text-left sm:grid-cols-3" >
562- < div className = "rounded-2xl border border-white/10 bg-white/5 p- 5" >
563- < p className = "text-xs uppercase tracking-wide text-white/60" > Total cards</ p >
541+ < div className = "grid gap-2 text-left sm:grid-cols-3 mt -3" >
542+ < div className = "bg-white/5" >
543+ < p className = "text-wrap text- xs uppercase tracking-wide text-white/60" > Total cards</ p >
564544 < p className = "mt-2 text-3xl font-semibold text-white" > { totalOwnedCards } </ p >
565545 </ div >
566- < div className = "rounded-2xl border border-white/10 bg-white/5 p- 5" >
567- < p className = "text-xs uppercase tracking-wide text-white/60" > Distinct sets</ p >
546+ < div className = "bg-white/5" >
547+ < p className = "text-wrap text- xs uppercase tracking-wide text-white/60" > Distinct sets</ p >
568548 < p className = "mt-2 text-3xl font-semibold text-white" > { distinctSets } </ p >
569549 </ div >
570- < div className = "rounded-2xl border border-white/10 bg-white/5 p- 5" >
571- < p className = "text-xs uppercase tracking-wide text-white/60" > Estimated value</ p >
550+ < div className = "bg-white/5" >
551+ < p className = "text-wrap text- xs uppercase tracking-wide text-white/60" > Estimated value</ p >
572552 < p className = "mt-2 text-3xl font-semibold text-emerald-400" > { formattedEstimatedValue } </ p >
573553 </ div >
574554 </ div >
@@ -634,6 +614,23 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
634614 />
635615 </ div >
636616 </ div >
617+ < div className = "hidden pb-4 lg:flex lg:justify-end" >
618+ < button
619+ type = "button"
620+ onClick = { toggleDesktopFilters }
621+ aria-expanded = { isDesktopFilterOpen }
622+ aria-controls = "desktop-filter-panel"
623+ className = "inline-flex items-center gap-2 rounded-full border border-white/20 bg-white/10 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/40"
624+ >
625+ < Filter size = { 16 } />
626+ { isDesktopFilterOpen ? "Hide Filters" : "Show Filters" }
627+ { activeFilterBadges . length > 0 && (
628+ < span className = "ml-2 rounded-full bg-indigo-500/40 px-2 py-0.5 text-xs font-semibold text-indigo-50" >
629+ { activeFilterBadges . length }
630+ </ span >
631+ ) }
632+ </ button >
633+ </ div >
637634 </ div >
638635 < div className = "mt-6" >
639636 < div className = "relative" >
@@ -715,9 +712,9 @@ const MyCollection = ( { initialCards = [], initialAuthState = false } ) => {
715712 { isDesktopFilterOpen && (
716713 < aside
717714 id = "desktop-filter-panel"
718- className = "hidden lg:fixed lg:inset-y-0 lg:right-0 lg:z-40 lg:flex lg:w-80 "
715+ className = "hidden lg:fixed lg:inset-y-0 lg:right-0 lg:z-40 lg:flex lg:w-72 "
719716 >
720- < div className = "flex h-full w-full flex-col border-l border-white/10 bg-black/40 px-4 py-8 backdrop-blur" >
717+ < div className = "flex h-full w-full flex-col border-l border-white/10 bg-black/40 px-2 py-8 backdrop-blur" >
721718 < FilterPanel
722719 className = "h-full overflow-y-auto rounded-2xl border-white/10 bg-black/60 text-white shadow-none"
723720 filters = { filters }
@@ -776,65 +773,11 @@ export async function getServerSideProps( { req } ) {
776773 }
777774 }
778775
779- let safeUserId ;
780- try {
781- safeUserId = ensureSafeUserId ( decodedUser ?. username ?? "" ) ;
782- } catch {
783- return {
784- redirect : {
785- destination : "/login" ,
786- permanent : false ,
787- } ,
788- } ;
789- }
790-
791- try {
792- const client = await clientPromise ;
793- const collection = client . db ( "cardPriceApp" ) . collection ( "myCollection" ) ;
794-
795- const agg = [
796- { $match : { userId : safeUserId } } ,
797- {
798- $project : {
799- _id : 1 ,
800- cardId : 1 ,
801- productName : 1 ,
802- setName : 1 ,
803- number : 1 ,
804- printing : 1 ,
805- rarity : 1 ,
806- condition : 1 ,
807- oldPrice : 1 ,
808- marketPrice : 1 ,
809- lowPrice : 1 ,
810- quantity : 1 ,
811- } ,
812- } ,
813- { $sort : { _id : 1 } } ,
814- ] ;
815-
816- const results = await collection . aggregate ( agg ) . toArray ( ) ;
817- const initialCards = results . map ( ( card ) => ( {
818- ...card ,
819- _id : card . _id ?. toString ?. ( ) ?? null ,
820- cardId : card . cardId === null || card . cardId === undefined ? null : String ( card . cardId ) ,
821- } ) ) ;
822-
823- return {
824- props : {
825- initialCards,
826- initialAuthState : true ,
827- } ,
828- } ;
829- } catch ( error ) {
830- console . error ( "getServerSideProps my-collection error:" , error ) ;
831- return {
832- props : {
833- initialCards : [ ] ,
834- initialAuthState : false ,
835- } ,
836- } ;
837- }
776+ return {
777+ props : {
778+ initialAuthState : Boolean ( decodedUser ) ,
779+ } ,
780+ } ;
838781}
839782
840783export default MyCollection ;
0 commit comments