From 184bfde1b5a0829d7a30ccdce06100ac7182d8cb Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:19:21 -0700 Subject: [PATCH 01/22] Simplify DataProvider to be base provider and handle both real and mock data --- src/app/providers/DataProvider.tsx | 46 ++---------------------------- 1 file changed, 2 insertions(+), 44 deletions(-) diff --git a/src/app/providers/DataProvider.tsx b/src/app/providers/DataProvider.tsx index 5fb46ed..07b94c1 100644 --- a/src/app/providers/DataProvider.tsx +++ b/src/app/providers/DataProvider.tsx @@ -1,57 +1,15 @@ 'use client' import { createContext, useContext, useState, useEffect, ReactNode } from 'react' -import { User } from '@/types/user' -import { Character } from '@/types/character' +import { User, Character, DataContextType } from '@/types' import { mockUser, mockCharacters } from '@/mocks' import { fetchUser } from '@/lib/api' -interface DataContextType { - user: User | null - setUser: (user: User | null) => void - characters: Character[] - setCharacters: (characters: Character[]) => void - loading: boolean -} - const DataContext = createContext(null) -// Toggle this to switch between mock and real data -const USE_MOCK_DATA = true - export function DataProvider({ children, userId }: { children: ReactNode; userId: number }) { - const [user, setUser] = useState(USE_MOCK_DATA ? mockUser : null) - const [characters, setCharacters] = useState(USE_MOCK_DATA ? mockCharacters : []) - const [loading, setLoading] = useState(false) - - useEffect(() => { - if (!USE_MOCK_DATA && !userId) { - return - } - - async function loadData() { - try { - setLoading(true) - - if (USE_MOCK_DATA) { - setUser(mockUser) - setCharacters(mockCharacters) - } else { - const userData = await fetchUser(userId) - setUser(userData) - } - } catch (error) { - console.error('Failed to load data:', error) - } finally { - setLoading(false) - } - } - - loadData() - }, [userId]) - return ( - + {children} ) From 0aec7076eac905efa9c1571002ef77cc2898856c Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:20:08 -0700 Subject: [PATCH 02/22] Move DataContextType to types directory and added index file to handle exports --- src/types/dataContext.ts | 9 +++++++++ src/types/index.ts | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 src/types/dataContext.ts create mode 100644 src/types/index.ts diff --git a/src/types/dataContext.ts b/src/types/dataContext.ts new file mode 100644 index 0000000..2b0d482 --- /dev/null +++ b/src/types/dataContext.ts @@ -0,0 +1,9 @@ +import { Character, User } from './index' + +export interface DataContextType { + user: User | null + setUser: (user: User | null) => void + characters: Character[] + setCharacters: (characters: Character[]) => void + loading: boolean +} \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..991dbbb --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,3 @@ +export type { Character } from './character' +export type { User } from './user' +export type { DataContextType } from './dataContext' \ No newline at end of file From 6da92bf776a3d3453b3a4c71351f26a0b8e48f87 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:20:36 -0700 Subject: [PATCH 03/22] Create ./DataProvider/index.ts to handle exports --- src/app/providers/index.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/app/providers/index.ts diff --git a/src/app/providers/index.ts b/src/app/providers/index.ts new file mode 100644 index 0000000..39f0c6e --- /dev/null +++ b/src/app/providers/index.ts @@ -0,0 +1,3 @@ +export { DataProvider, useData } from './DataProvider' +export { RealDataProvider } from './RealDataProvider' +export { MockDataProvider } from './MockDataProvider' \ No newline at end of file From 28ec3c015e6bab5c8a8013a690ea370134eac2e2 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:53:42 -0700 Subject: [PATCH 04/22] Refine dataprovider to be base for seperate providers --- src/app/providers/DataProvider.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/providers/DataProvider.tsx b/src/app/providers/DataProvider.tsx index 07b94c1..1de43ba 100644 --- a/src/app/providers/DataProvider.tsx +++ b/src/app/providers/DataProvider.tsx @@ -1,15 +1,13 @@ 'use client' import { createContext, useContext, useState, useEffect, ReactNode } from 'react' -import { User, Character, DataContextType } from '@/types' -import { mockUser, mockCharacters } from '@/mocks' -import { fetchUser } from '@/lib/api' +import { DataContextType } from '@/types' const DataContext = createContext(null) -export function DataProvider({ children, userId }: { children: ReactNode; userId: number }) { +export function DataProvider({ children, value }: { children: ReactNode; value: DataContextType }) { return ( - + {children} ) From b007a86a3ab0660eb95ef86b71a2888c35a364bd Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:54:01 -0700 Subject: [PATCH 05/22] Create seperate provider to handle mock data --- src/app/providers/MockDataProvider.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/app/providers/MockDataProvider.tsx diff --git a/src/app/providers/MockDataProvider.tsx b/src/app/providers/MockDataProvider.tsx new file mode 100644 index 0000000..ac4a900 --- /dev/null +++ b/src/app/providers/MockDataProvider.tsx @@ -0,0 +1,26 @@ +'use client' + +import { useState, ReactNode } from 'react' +import { DataProvider } from '@/app/providers' +import { User, Character } from '@/types' +import {mockUser, mockCharacters } from '@/mocks' + +export function MockDataProvider({ children }: { children: ReactNode}) { + const [ user, setUser ] = useState(mockUser) + const [ characters, setCharacters ] = useState(mockCharacters) + + return ( + + {children} + + ) +} From 4bc9b1018eaecb08f8a2f8dabe7b9326ad3d43a2 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:54:17 -0700 Subject: [PATCH 06/22] Update DataContextType interface --- src/types/dataContext.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/types/dataContext.ts b/src/types/dataContext.ts index 2b0d482..1bc0c63 100644 --- a/src/types/dataContext.ts +++ b/src/types/dataContext.ts @@ -1,9 +1,12 @@ +import { Dispatch, SetStateAction } from 'react' import { Character, User } from './index' + export interface DataContextType { user: User | null - setUser: (user: User | null) => void + setUser: Dispatch> characters: Character[] - setCharacters: (characters: Character[]) => void - loading: boolean + setCharacters: Dispatch> + loading: boolean, + isMockData: boolean } \ No newline at end of file From 864fc5ea2fe24b54d91d39bd6b73ecb35a14923a Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 16:54:35 -0700 Subject: [PATCH 07/22] Update providers export file --- src/app/providers/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/providers/index.ts b/src/app/providers/index.ts index 39f0c6e..ee7d7b0 100644 --- a/src/app/providers/index.ts +++ b/src/app/providers/index.ts @@ -1,3 +1,4 @@ +export { AppDataProvider } from './helper/AppDataProvider' export { DataProvider, useData } from './DataProvider' export { RealDataProvider } from './RealDataProvider' export { MockDataProvider } from './MockDataProvider' \ No newline at end of file From 0d30e2de4e3fb323f656ca41621a078c85f9d816 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:05:17 -0700 Subject: [PATCH 08/22] Add missed typing --- src/app/providers/MockDataProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/providers/MockDataProvider.tsx b/src/app/providers/MockDataProvider.tsx index ac4a900..20ac872 100644 --- a/src/app/providers/MockDataProvider.tsx +++ b/src/app/providers/MockDataProvider.tsx @@ -7,7 +7,7 @@ import {mockUser, mockCharacters } from '@/mocks' export function MockDataProvider({ children }: { children: ReactNode}) { const [ user, setUser ] = useState(mockUser) - const [ characters, setCharacters ] = useState(mockCharacters) + const [ characters, setCharacters ] = useState(mockCharacters) return ( Date: Tue, 9 Dec 2025 17:05:38 -0700 Subject: [PATCH 09/22] Created seperate provider to handle data coming in from sg_backend --- src/app/providers/RealDataProvider.tsx | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/app/providers/RealDataProvider.tsx diff --git a/src/app/providers/RealDataProvider.tsx b/src/app/providers/RealDataProvider.tsx new file mode 100644 index 0000000..f9b1722 --- /dev/null +++ b/src/app/providers/RealDataProvider.tsx @@ -0,0 +1,50 @@ +'use client' + +import { useState, ReactNode, useEffect } from 'react' +import { DataProvider } from '@/app/providers' +import {User, Character } from '@/types' +import { fetchUser } from '@/lib/api' + +export function RealDataProvider({ children, userId }: { children: ReactNode, userId?: number}) { + const [ user, setUser ] = useState(null) + const [ characters, setCharacters ] = useState([]) + const [ loading, setLoading ] = useState(true) + + useEffect(() =>{ + if(!userId) { + setLoading(false) + return + } + + async function loadData() { + try { + setLoading(true) + + const userData = await fetchUser(userId!) + setUser(userData) + + } catch (error) { + console.error('Failed to load data:', error) + } finally { + setLoading(false) + } + } + + loadData() + }, [userId]) + + return ( + + {children} + + ) +} From 9813efc159cf0761ce5404e109154a4b4394bfdf Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:06:06 -0700 Subject: [PATCH 10/22] Add AppDataProvider to handle which provider is being used --- src/app/providers/helper/AppDataProvider.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/app/providers/helper/AppDataProvider.tsx diff --git a/src/app/providers/helper/AppDataProvider.tsx b/src/app/providers/helper/AppDataProvider.tsx new file mode 100644 index 0000000..8f8fab3 --- /dev/null +++ b/src/app/providers/helper/AppDataProvider.tsx @@ -0,0 +1,20 @@ +'use client' + +import { ReactNode } from 'react' +import { MockDataProvider, RealDataProvider } from '@/app/providers' + +const USE_MOCK_DATA = false + +export function AppDataProvider({ + children, + userId +}: { + children: ReactNode, + userId?: number +}) { + if(USE_MOCK_DATA) { + return {children} + } + + return {children} +} \ No newline at end of file From f9e1d3a0d88f9679ede50d422f5d7bea55c42d0f Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:06:20 -0700 Subject: [PATCH 11/22] Update layout to use new provider flow --- src/app/layout.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b4ebdb4..56f3e88 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next' import { beau_rivage, geistSans, geistMono } from './fonts' import './globals.css' import Header from '../components/layout/Header/header' -import { DataProvider } from './providers/DataProvider' +import { AppDataProvider } from '@/app/providers' export const metadata: Metadata = { title: 'SilverGuild', @@ -19,7 +19,7 @@ export default function RootLayout({ - +
@@ -28,7 +28,7 @@ export default function RootLayout({ {children}
- + ) From 7ebb0b6d6499c0f0e1e2910815e12b2edfade43a Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:18:26 -0700 Subject: [PATCH 12/22] Add extractAll helper method --- src/lib/jsonApiClient.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/jsonApiClient.ts b/src/lib/jsonApiClient.ts index a561636..cb7e2cf 100644 --- a/src/lib/jsonApiClient.ts +++ b/src/lib/jsonApiClient.ts @@ -14,3 +14,14 @@ export function extractSingle(response: JsonApiResponse): T & { id: number const item = response.data[0] return { id: item.id, ...item.attributes } } + +export function extractAll(response: JsonApiResponse): Array { + if (!response.data || response.data.length == 0) { + return [] + } + + return response.data.map(item => ({ + id: item.id, + ...item.attributes + })) +} From b2751c8d82d15e11f79ff998ac98f6eba49b8eae Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:18:36 -0700 Subject: [PATCH 13/22] Update endpoints --- src/lib/config.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/config.ts b/src/lib/config.ts index 6c4b2c5..f50ffb3 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -9,7 +9,6 @@ export const SG_API_ENDPOINTS = { users: '/users', // eslint-disable-next-line @typescript-eslint/no-unused-vars userById: (id: number) => `/users/${id}`, - characters: '/characters', - // eslint-disable-next-line @typescript-eslint/no-unused-vars - characterById: (id: number) => `/characters/$(id)`, + charactersByUserId: (userId: number) => `/user/${userId}/characters`, + characterById: (id: number) => `/characters/${id}` } as const From 1a5782bab04182f1fd08225ac38c20e85f5feb67 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:19:01 -0700 Subject: [PATCH 14/22] Add fetchUserCharacters to api fetch methods --- src/lib/api.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/api.ts b/src/lib/api.ts index be5f858..f9ce88c 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,6 +1,6 @@ import { SG_API_BASE_URL, SG_API_ENDPOINTS } from './config' -import { User } from '@/types/user' -import { JsonApiResponse, extractSingle } from './jsonApiClient' +import { User, Character } from '@/types' +import { JsonApiResponse, extractSingle, extractAll } from './jsonApiClient' export async function apiRequest(endpoint: string, options?: RequestInit): Promise { const response = await fetch(`${SG_API_BASE_URL}${endpoint}`, { @@ -22,3 +22,8 @@ export async function fetchUser(id: number): Promise { const json = await apiRequest>(SG_API_ENDPOINTS.userById(id)) return extractSingle(json) } + +export async function fetchUserCharacters(id: number): Promise { + const json = await apiRequest>(SG_API_ENDPOINTS.charactersByUserId(id)) + return extractAll(json) +} \ No newline at end of file From 7e46266405c60677f2af92a56d1e06d2efd758ca Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:33:21 -0700 Subject: [PATCH 15/22] Update test userId --- src/app/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 56f3e88..6abe06f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -19,7 +19,7 @@ export default function RootLayout({ - + // Hard set for testing purposes
From 0f5e76358ee44d0a9c6fd370b42b8413b21c1205 Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:34:27 -0700 Subject: [PATCH 16/22] Add call to fetchUserCharacters and set context state with characters roster from sg_backend --- src/app/providers/RealDataProvider.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/providers/RealDataProvider.tsx b/src/app/providers/RealDataProvider.tsx index f9b1722..51dd92f 100644 --- a/src/app/providers/RealDataProvider.tsx +++ b/src/app/providers/RealDataProvider.tsx @@ -2,8 +2,8 @@ import { useState, ReactNode, useEffect } from 'react' import { DataProvider } from '@/app/providers' -import {User, Character } from '@/types' -import { fetchUser } from '@/lib/api' +import { User, Character } from '@/types' +import { fetchUser, fetchUserCharacters } from '@/lib/api' export function RealDataProvider({ children, userId }: { children: ReactNode, userId?: number}) { const [ user, setUser ] = useState(null) @@ -20,8 +20,13 @@ export function RealDataProvider({ children, userId }: { children: ReactNode, us try { setLoading(true) - const userData = await fetchUser(userId!) + const [ userData, characterData ] = await Promise.all([ + fetchUser(userId!), + fetchUserCharacters(userId!) + ]) + setUser(userData) + setCharacters(characterData) } catch (error) { console.error('Failed to load data:', error) From 2b3a72f168de1acd5d55b74bc0e3e13106dc66bf Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:34:37 -0700 Subject: [PATCH 17/22] Fix typo in endpoints --- src/lib/config.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/config.ts b/src/lib/config.ts index f50ffb3..967a06f 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -6,9 +6,7 @@ export const APP_NAME = 'SilverGuild' // API Endpoints export const SG_API_ENDPOINTS = { - users: '/users', - // eslint-disable-next-line @typescript-eslint/no-unused-vars userById: (id: number) => `/users/${id}`, - charactersByUserId: (userId: number) => `/user/${userId}/characters`, + charactersByUserId: (userId: number) => `/users/${userId}/characters`, characterById: (id: number) => `/characters/${id}` } as const From e81e02f550dd4ad2356653bfa7d2c901cff3648d Mon Sep 17 00:00:00 2001 From: elysableu Date: Tue, 9 Dec 2025 17:50:47 -0700 Subject: [PATCH 18/22] Fix linter errors --- package.json | 1 + src/app/layout.tsx | 2 +- src/app/profile/components/CharacterRosterCard.tsx | 5 ++++- src/app/profile/components/ProfileDetails.tsx | 12 ++++++++---- src/app/providers/DataProvider.tsx | 2 +- src/components/layout/Header/header.tsx | 4 ++-- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 871cf0a..1b370ba 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", + "lint:fix": "next lint --fix", "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css}\"", "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css}\"", "test": "jest", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6abe06f..08fabb0 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -19,7 +19,7 @@ export default function RootLayout({ - // Hard set for testing purposes + {/* Hard set for testing purposes */}
diff --git a/src/app/profile/components/CharacterRosterCard.tsx b/src/app/profile/components/CharacterRosterCard.tsx index 8156017..c7a5c08 100644 --- a/src/app/profile/components/CharacterRosterCard.tsx +++ b/src/app/profile/components/CharacterRosterCard.tsx @@ -1,3 +1,4 @@ +import Image from 'next/image' import { Character } from '@/types/character' interface CharacterRosterCardProps { @@ -8,9 +9,11 @@ export default function CharacterRosterCard({ character }: CharacterRosterCardPr return (
- {character.name}
diff --git a/src/app/profile/components/ProfileDetails.tsx b/src/app/profile/components/ProfileDetails.tsx index 4129ff7..e0a15ec 100644 --- a/src/app/profile/components/ProfileDetails.tsx +++ b/src/app/profile/components/ProfileDetails.tsx @@ -1,3 +1,4 @@ +import Image from 'next/image' import { User } from '@/types/user' interface ProfileDetailsProps { @@ -8,10 +9,13 @@ export default function ProfileDetails({ user }: ProfileDetailsProps) { return (
- {user.username}
diff --git a/src/app/providers/DataProvider.tsx b/src/app/providers/DataProvider.tsx index 1de43ba..221f135 100644 --- a/src/app/providers/DataProvider.tsx +++ b/src/app/providers/DataProvider.tsx @@ -1,6 +1,6 @@ 'use client' -import { createContext, useContext, useState, useEffect, ReactNode } from 'react' +import { createContext, useContext, ReactNode } from 'react' import { DataContextType } from '@/types' const DataContext = createContext(null) diff --git a/src/components/layout/Header/header.tsx b/src/components/layout/Header/header.tsx index 7150f90..3e71121 100644 --- a/src/components/layout/Header/header.tsx +++ b/src/components/layout/Header/header.tsx @@ -1,13 +1,13 @@ import Link from 'next/link' +import Image from 'next/image' export default function Header() { return (
- {/* eslint-disable-next-line @next/next/no-img-element */} - sg_logo + sg_logo