Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f3bd28b
Add mock data for user and characters
elysableu Nov 18, 2025
88881e7
Update tsconfig file so @/* paths to app root not computer root
elysableu Nov 18, 2025
6b32fe8
Add usr and character interface files
elysableu Nov 18, 2025
140a29f
Update mock data to use associated interfaces
elysableu Nov 18, 2025
66ec04c
Wrap main app in DataProvider
elysableu Nov 18, 2025
1a9e9a1
Updating typing and add context null check
elysableu Nov 18, 2025
de392f3
Remove unnecessary useState
elysableu Nov 18, 2025
6e8f78c
Move components into components folder
elysableu Nov 18, 2025
4b86dbb
Update typing
elysableu Nov 18, 2025
3f775ae
Add typing, null check, and basic user detail html
elysableu Nov 18, 2025
35d6f8a
Remove unecessary imports'
elysableu Nov 18, 2025
50db605
Move components back to /app for routing
elysableu Nov 18, 2025
6c4ce6b
Update variable name
elysableu Nov 18, 2025
1f2a3c3
Add typing to states
elysableu Nov 18, 2025
310c96a
Add format characters to display in character roster using CharacterR…
elysableu Nov 24, 2025
ed3e4f8
Update config.ts with app constants including base_url and sg_api_end…
elysableu Nov 24, 2025
75c3b25
Fix typo
elysableu Nov 24, 2025
5451ec6
Move null checker to parent component
elysableu Nov 24, 2025
b509df3
Update userHome layout
elysableu Nov 24, 2025
c8a1842
Improve SoC by moving api fetch calls into its own api.ts, leaving Da…
elysableu Nov 24, 2025
9f93724
Add endpoints for user and character fetch by id
elysableu Nov 24, 2025
60391b4
Temporarily suspend main workflow
elysableu Nov 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
name: Cypress Tests
# name: Cypress Tests

on: [push]
# on: [push]

jobs:
cypress-run:
runs-on: ubuntu-latest
environment: Test
steps:
- name: Checkout
uses: actions/checkout@v3
# jobs:
# cypress-run:
# runs-on: ubuntu-latest
# environment: Test
# steps:
# - name: Checkout
# uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '22.13.1'
cache: 'npm'
# - name: Setup Node.js
# uses: actions/setup-node@v3
# with:
# node-version: '22.13.1'
# cache: 'npm'

- name: Install dependencies
run: npm ci
# - name: Install dependencies
# run: npm ci

- name: Build
run: npm run build
# - name: Build
# run: npm run build
1 change: 0 additions & 1 deletion src/app/character/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

export default function Character() {
return (
<div className="flex justify-center align-items w-full h-1vh">
Expand Down
17 changes: 11 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +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';

export const metadata: Metadata = {
title: "SilverGuild",
Expand All @@ -18,12 +19,16 @@ export default function RootLayout({
<body
className={`${geistSans.variable} ${geistMono.variable} ${beau_rivage.variable} antialiased`}
>
<div className="top-0">
<Header />
</div>
<main>
{children}
</main>
<DataProvider>
<div className="flex flex-col w-full h-screen">
<div className="top-0 left-0 w-full ">
<Header />
</div>
<main className="flex items-center justify-center w-full h-screen pt-40">
{children}
</main>
</div>
</DataProvider>
</body>
</html>
);
Expand Down
10 changes: 1 addition & 9 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
'use client'
import { useState } from 'react';

export default function Home() {
const [userInfo, setUserInfo] = useState({
name: "Elysa",
username: "bleu7",
email: "bleu@gmail.com",
characterCount: 7
})

export default function Home() {
return (
<div className="min-h-screen h-screen max-h-screen overflow-hidden fixed inset-0 w-full mt-0 flex flex-col justify-center align-items">
<h1 className="text-8xl text-center title-font">SilverGuild</h1>
Expand Down
40 changes: 40 additions & 0 deletions src/app/providers/DataProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use client';

import { createContext, useContext, useState, ReactNode } from 'react';
import { User } from '@/types/user';
import { Character } from '@/types/character';
import { SG_API_BASE_URL, SG_API_ENDPOINTS } from '@/lib/config';
import { mockUser } from '@/lib/mock/userData';
import { mockCharacters} from '@/lib/mock/characterData';

interface DataContextType {
user: User | null;
setUser: (user: User | null) => void;
characters: Character[];
setCharacters: (characters: Character[]) => void;
}

const DataContext = createContext<DataContextType | null>(null);

const USE_MOCK_DATA = true;

export function DataProvider({ children }: {children : ReactNode}) {
const [ user, setUser ] = useState<User | null>(USE_MOCK_DATA ? mockUser : null);
const [ characters, setCharacters ] = useState<Character[]>(USE_MOCK_DATA ? mockCharacters : []);

return (
<DataContext.Provider value={{ user, setUser, characters, setCharacters }}>
{children}
</DataContext.Provider>
);
}

export const useData = () => {
const context = useContext(DataContext);

if (!context) {
throw new Error('useData must be used within a DataProvider')
}

return context;
};
31 changes: 31 additions & 0 deletions src/app/userHome/components/CharacterRoster.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Character } from '@/types/character';
import CharacterRosterCard from './CharacterRosterCard';

interface CharacterRosterProps {
characters: Character[];
userId: number;
}

export default function CharacterRoster({ characters }: CharacterRosterProps) {
if (!characters) {
return <div>No user data available!</div> // Receive error from back end display
}

console.log(characters);


let roster = characters.map((character) => {
return (
<CharacterRosterCard
key = {character.id}
character={character}
/>
)
} )

return (
<div className="flex flex-col items-center flex-2 bg-cyan-950 m-4 p-4 rounded-lg w-full">
{ roster }
</div>
)
};
34 changes: 34 additions & 0 deletions src/app/userHome/components/CharacterRosterCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Character } from '@/types/character';

interface CharacterRosterCardProps {
character: Character;
}

export default function CharacterRosterCard({character}: CharacterRosterCardProps) {
return (
<div className="flex items-center bg-gray-800 m-2 p-4 rounded-lg w-full">
<div className="w-16 h-16 rounded-full bg-gray-300 mr-2 mb-4 overflow-hidde shrink-0">
<img src="" alt={character.name}/>
</div>
<div className="flex-1 w-full text-center">
<h3>{character.name}</h3>
<dl className="flex w-full justify-around mt-2">
<div className="flex mr-2">
<dt>Level:</dt>
<dd>{character.level}</dd>
</div>

<div className="flex mr-2">
<dt>Class:</dt>
<dd>{character.character_class_id}</dd>
</div>

<div className="flex mr-2">
<dt>Race:</dt>
<dd>{character.race_id}</dd>
</div>
</dl>
</div>
</div>
);
};
25 changes: 17 additions & 8 deletions src/app/userHome/components/ProfileDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
export default function ProfileDetails() {
import { User } from '@/types/user';

interface ProfileDetailsProps {
user: User;
}

export default function ProfileDetails({ user }: ProfileDetailsProps) {
return (
<div>
<div>
{/* <img src={""} alt={""}></img> */}
</div>
<h3></h3>
<div>

<div className="flex flex-col items-center flex-1 bg-cyan-950 m-4 p-4 rounded-lg">
<div className="w-32 h-32 rounded-full bg-gray-300 mb-4 overflow-hidden">
<img src="" alt={ user.username }/>
</div>
<dl>
<dt>Username:</dt>
<dd>{ user.username }</dd>

<dt>Email:</dt>
<dd>{ user.email }</dd>
</dl>
</div>
);
}
15 changes: 13 additions & 2 deletions src/app/userHome/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
'use client';

import { useData } from '@/app/providers/DataProvider';
import ProfileDetails from './components/ProfileDetails';
import CharacterRoster from './components/CharacterRoster';

export default function UserHome() {
const { user, characters } = useData();

if (!user) {
return <div>Loading user...</div>; // Receive error from back end display
}

return (
<div className="flex justify-center align-items w-full h-1vh">
<ProfileDetails />
<div className="flex justify-around items-center w-full h-screen">
<ProfileDetails user={user} />
<CharacterRoster characters={characters} userId={user.id} />
</div>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/components/layout/Header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import Link from 'next/link'

export default function Header() {
return (
<header className="fixed top-0 w-full bg-transparent shadow-lg z-50">
<div className="flex justify-between items-center my-10">
<header className="fixed top-0 w-full bg-black shadow-lg z-50">
<div className="flex justify-between items-center my-4">
<div className="basis-2/10 ml-10">
<Link href="/"><img className="size-32" src="/logo.svg"/></Link>
<Link href="/"><img className="size-28" src="/logo.svg"/></Link>
</div>
<nav className="basis-3/10 mr-10">
<ul className="flex flex-row mx-auto px-6 py-3 justify-between items-center text-xl">
Expand Down
26 changes: 26 additions & 0 deletions src/lib/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { SG_API_BASE_URL, SG_API_ENDPOINTS } from './config';
import { Character } from '@/types/character';
import { User } from '@/types/user';

export async function apiRequest<T>(
endpoint: string,
options?: RequestInit
): Promise<T> {
const response = await fetch(`${SG_API_BASE_URL}${endpoint}`, {
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
...options,
});

if(!response.ok) {
throw new Error(`API ERROR: ${response.statusText}`);
}

return response.json();
}

export async function fetchUser(id: number): Promise<User> {
return apiRequest<User>(SG_API_ENDPOINTS.userById(id))
}
13 changes: 13 additions & 0 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SG API configuration
export const SG_API_BASE_URL = 'http://localhost:3000/api/v1';

// Other app constants
export const APP_NAME = 'SilverGuild';

// API Endpoints
export const SG_API_ENDPOINTS = {
users: '/users',
userById: (id: number ) => `/users/${id}`,
characters: '/characters',
characterById: (id: number) => `/characters/$(id)`,
} as const;
7 changes: 7 additions & 0 deletions src/lib/mock/characterData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Character } from '@/types/character';

export const mockCharacters: Character[] = [
{ id: 1, name: "Theren Nightwhisper", level: 3, experience_points: 345, alignment: "Chaotic Good" , background: "Folk Hero", user_id: 1, character_class_id: "wizard", race_id: "half-elf", subclass_id: "evocation", subrace_id: "", languages: [ "common", "elvish" ]},
{ id: 2, name: "Mira Stormhaven", level: 8, experience_points: 853, alignment: "Lawful Neutral" , background: "Acolyte", user_id: 1, character_class_id: "fighter", race_id: "halfling", subclass_id: "champion", subrace_id: "lightfoot-halfling", languages: [ "common", "halfling" ]},
{ id: 3, name: "Kaelynn Thornwick", level: 1, experience_points: 121, alignment: "Neutral Good" , background: "Hermit", user_id: 1, character_class_id: "druid", race_id: "gnome", subclass_id: "", subrace_id: "rock-gnome", languages: [ "common", "gnomish" ]}
]
7 changes: 7 additions & 0 deletions src/lib/mock/userData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { User } from '@/types/user';

export const mockUser: User = {
id: 1,
username: "John Mockery",
email: "mockjohnny@gmail.com"
}
15 changes: 15 additions & 0 deletions src/types/character.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// types/character.ts
export interface Character {
id: number;
name: string;
level: number;
experience_points: number;
alignment: string;
background: string;
user_id: number;
character_class_id: string;
race_id: string;
subclass_id: string;
subrace_id: string;
languages: string[]
}
6 changes: 6 additions & 0 deletions src/types/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// types/user.ts
export interface User {
id: number;
username: string;
email: string;
}
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
"name": "next"
}
],
"baseUrl": "src",
"baseUrl": ".",
"paths": {
"@/*": ["/*"],
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
Expand Down