Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
fe24e73
Add API URL to local environment variables
smithyhelen Oct 26, 2025
9faa95e
Add Discord authentication component
smithyhelen Oct 26, 2025
46845ba
Add HerdMapOverlay component for herd tracking
smithyhelen Oct 26, 2025
2a3e2cb
Add discordApiService with various API functions
smithyhelen Oct 26, 2025
45f8fa6
Enhance README with Discord integration details
smithyhelen Oct 26, 2025
08d6e56
Add DiscordAuth component to layout
smithyhelen Oct 26, 2025
6abe89d
Add conditional HerdMapOverlay to Nez Perce Valley page
smithyhelen Oct 26, 2025
2244d1f
Change deployment trigger to main branch
smithyhelen Oct 26, 2025
14e2646
Remove duplicate import of DiscordAuth component
smithyhelen Oct 26, 2025
09ace4c
Reorder import statements in page.tsx
smithyhelen Oct 26, 2025
0c14261
Fix import statements formatting in page.tsx
smithyhelen Oct 26, 2025
15b9041
Reorder import statements in page.tsx
smithyhelen Oct 26, 2025
2b2aef3
Refactor imports in HerdMapOverlay component
smithyhelen Oct 26, 2025
2badc66
Refactor imports in HerdMapOverlay component
smithyhelen Oct 26, 2025
e242933
Fix import statements in Nez Perce Valley page
smithyhelen Oct 26, 2025
d724804
Remove linting job from nextjs.yml
smithyhelen Oct 26, 2025
1ac3137
Remove lint dependency from build step
smithyhelen Oct 26, 2025
ba0d870
Add Discord authentication component
smithyhelen Oct 26, 2025
419c03b
Delete src/components/src/components directory
smithyhelen Oct 26, 2025
8a6a015
Add production environment variable for base URL
smithyhelen Oct 27, 2025
ca31bb9
Update baseUrl to include default value
smithyhelen Oct 27, 2025
30fab26
Update README.md
smithyhelen Oct 27, 2025
54103f4
Fix baseUrl assignment syntax error
smithyhelen Oct 27, 2025
c386b1f
Add unoptimized images configuration
smithyhelen Oct 27, 2025
3371e95
Update next.config.js
smithyhelen Oct 27, 2025
7340e70
Remove redundant module.exports line
smithyhelen Oct 27, 2025
25519a2
Remove experimental images from next.config.js
smithyhelen Oct 27, 2025
7295f34
Remove experimental images from next.config.js
smithyhelen Oct 27, 2025
aced461
Remove experimental.images from Next.js config
smithyhelen Oct 27, 2025
2f205ef
Fix formatting and update images configuration
smithyhelen Oct 27, 2025
1809a47
Refactor NotFoundPage to use Suspense and content
smithyhelen Oct 27, 2025
e20cada
Refactor NezPerceValleyPage to use state for login
smithyhelen Oct 27, 2025
6e0e39b
Refactor NotFound component with login check
smithyhelen Oct 27, 2025
5cc7870
Refactor NotFoundPage for client-side rendering
smithyhelen Oct 27, 2025
12b6367
Refactor NotFoundPage to always render DiscordAuth
smithyhelen Oct 27, 2025
62fa132
Refactor NotFoundPage component styling and structure
smithyhelen Oct 27, 2025
67d9672
Dynamically import DiscordAuth for client-side rendering
smithyhelen Oct 27, 2025
d760910
Add ClientDiscordAuth component with dynamic import
smithyhelen Oct 27, 2025
fb4cbef
Replace DiscordAuth with ClientDiscordAuth component
smithyhelen Oct 27, 2025
400d4c0
Refactor next.config.js for clarity and updates
smithyhelen Oct 27, 2025
0f28ae5
Commit this change with message: Fix asset paths for GitHub Pages dep…
smithyhelen Oct 27, 2025
0e7e98e
Fix asset paths for GitHub Pages deployment
smithyhelen Oct 27, 2025
00bf88f
Disable ESLint during builds
smithyhelen Oct 27, 2025
0fe38b6
Fix environment variables for GitHub Pages deployment
smithyhelen Oct 27, 2025
8fd3701
Fix formatting of environment variables in nextjs.yml
smithyhelen Oct 27, 2025
1b05568
Fix indentation for export static assets step
smithyhelen Oct 27, 2025
cf9fd7b
Fix indentation for Export static application assets step
smithyhelen Oct 27, 2025
7691ef1
Remove basePath from config to fix runtime error
smithyhelen Oct 27, 2025
09c9cfb
Refactor next.config.js for cleaner configuration
smithyhelen Oct 27, 2025
6211269
Refactor DiscordAuth component for improved structure
smithyhelen Oct 27, 2025
a71d987
Remove unoptimized images configuration
smithyhelen Oct 27, 2025
d96f9f3
Update next.config.js
smithyhelen Oct 27, 2025
ae1b874
Update next.config.js
smithyhelen Oct 27, 2025
bce1d26
Update nextjs.yml
smithyhelen Oct 27, 2025
ce600f3
Update tsconfig.json
smithyhelen Oct 27, 2025
ae335e8
Update discordApiService.ts
smithyhelen Oct 27, 2025
8cadc29
Update DiscordAuth.tsx
smithyhelen Oct 27, 2025
590c1d7
Update ClientDiscordAuth.tsx
smithyhelen Oct 28, 2025
aa0f96e
Delete src/components/DiscordAuth.tsx
smithyhelen Oct 28, 2025
bc2cd11
Update ClientDiscordAuth.tsx
smithyhelen Oct 28, 2025
24a8643
Update layout.tsx
smithyhelen Oct 28, 2025
da248c8
Update ClientDiscordAuth.tsx
smithyhelen Oct 28, 2025
272b725
Update ClientDiscordAuth.tsx
smithyhelen Oct 28, 2025
93a15dd
Update ClientDiscordAuth.tsx
smithyhelen Oct 28, 2025
4d8f0c7
Update discordApiService.ts
smithyhelen Oct 28, 2025
56d9bea
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
c4efe5a
Update useStorage.ts
smithyhelen Oct 28, 2025
1d3d3cc
Update SettingsProvider.tsx
smithyhelen Oct 28, 2025
98457d4
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
486e206
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
16cda1c
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
f398545
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
c69a82f
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
4ddeacb
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
cafdb8d
Update useTutorial.tsx
smithyhelen Oct 28, 2025
e8cbbd9
Update useTutorial.tsx
smithyhelen Oct 28, 2025
c151d08
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
85a788f
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
0f09018
Update HuntingMapPage.tsx
smithyhelen Oct 28, 2025
cf2b107
Update ApplicationProvider.tsx
smithyhelen Oct 28, 2025
0ceb83a
Update ApplicationProvider.tsx
smithyhelen Oct 28, 2025
62e86d8
Update ApplicationProvider.tsx
smithyhelen Oct 28, 2025
287edf3
Update Toolbar.tsx
smithyhelen Oct 28, 2025
fc1055d
Update index.ts
smithyhelen Oct 28, 2025
805f0ad
Update index.ts
smithyhelen Oct 28, 2025
dcc8b85
Update useTutorial.tsx
smithyhelen Oct 28, 2025
79b693e
Update useTutorial.tsx
smithyhelen Oct 28, 2025
c30ff06
Update useTutorial.tsx
smithyhelen Oct 28, 2025
6b4fa6c
Update useTutorialManager.ts
smithyhelen Oct 28, 2025
d49b8c4
Update useTutorialManager.ts
smithyhelen Oct 28, 2025
1e77194
Delete src/components/HuntingMapTutorial directory
smithyhelen Oct 28, 2025
9821679
Delete src/contexts/TutorialContext directory
smithyhelen Oct 28, 2025
3b1618b
Delete src/hooks/useTutorial.tsx
smithyhelen Oct 28, 2025
46419b5
Delete src/hooks/useTutorialManager.ts
smithyhelen Oct 28, 2025
c95da54
Force cache refresh
smithyhelen Oct 28, 2025
2390d60
Restore original next.config.js with webpack configuration
smithyhelen Oct 28, 2025
e556e85
Restore complete tutorial functionality
smithyhelen Oct 28, 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
1 change: 1 addition & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_API_URL=http://65.109.100.181:8080
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_BASE_URL=https://smithyhelen.github.io/woth-toolbox
56 changes: 8 additions & 48 deletions .github/workflows/nextjs.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: Deploy site to Github Pages

# Runs when pushing new tags
# Runs when pushing to main branch
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
branches:
- main

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
Expand Down Expand Up @@ -48,43 +48,13 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
run: pnpm install

lint:
name: Lint code
runs-on: ubuntu-latest
needs: deps
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Restore application dependencies
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-node-modules-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
fail-on-cache-miss: true

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- name: Perform code linting
run: pnpm lint

# Build job
build:
name: Build
runs-on: ubuntu-latest
environment: production
needs:
- lint
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -111,12 +81,8 @@ jobs:

- name: Configure GitHub Pages
uses: actions/configure-pages@v4
with:
# Automatically inject basePath in your Next.js configuration file and disable
# server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).
#
# You may remove this line if you want to manage the configuration yourself.
static_site_generator: next



- name: Configure output cache
uses: actions/cache@v4
Expand All @@ -131,15 +97,9 @@ jobs:

- name: Export static application assets
env:
NEXT_PUBLIC_BASE_PATH: ${{ vars.NEXT_PUBLIC_BASE_PATH }}
NEXT_PUBLIC_BASE_URL: ${{ vars.NEXT_PUBLIC_BASE_URL }}
NEXT_PUBLIC_FIREBASE_API_KEY: ${{ vars.NEXT_PUBLIC_FIREBASE_API_KEY }}
NEXT_PUBLIC_FIREBASE_APP_ID: ${{ vars.NEXT_PUBLIC_FIREBASE_APP_ID }}
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{ vars.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN }}
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ vars.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }}
NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{ vars.NEXT_PUBLIC_FIREBASE_PROJECT_ID }}
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: ${{ vars.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET }}
NEXT_PUBLIC_GOOGLE_ANALYTICS: ${{ vars.NEXT_PUBLIC_GOOGLE_ANALYTICS }}
NEXT_PUBLIC_BASE_PATH: "/woth-toolbox"
NEXT_PUBLIC_BASE_URL: "https://smithyhelen.github.io/woth-toolbox"
NEXT_PUBLIC_API_URL: "http://65.109.100.181:8080"
run: pnpm build

- name: Upload assets as artifacts
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# WOTH Toolbox - Discord Enhanced 🦌

> This is a fork of [codeaid/woth-toolbox](https://github.com/codeaid/woth-toolbox) with Discord integration for personal herd tracking.

## Discord Integration Features
- Login with Discord to see your personally tracked herds on the maps
- Automatic map filtering - only shows herds from the currently selected map
- Color-coded markers: 🏆 Trophy, ✅ Leave, ⏳ Monitor, ❌ Cull
- Real-time sync with your Discord bot's database

## Credits
- **Original WOTH Toolbox** by [codeaid](https://github.com/codeaid)
- **Map Data** courtesy of Nine Rocks Games and THQ Nordic
- **Discord Integration** for "Antlers in the Mist" community

---
![Way Of The Hunter Logo](docs/woth-logo.png)

This interactive web application contains a suite of tools that can be used
Expand Down
2 changes: 2 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const getLocalIdentHash = (context, localIdentName, localName) =>
/** @type {import('next').NextConfig} */
const config = {
basePath: process.env.NEXT_PUBLIC_BASE_PATH,

// Don't run linter during production builds
eslint: {
ignoreDuringBuilds: true,
},
Expand Down
2 changes: 2 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GoogleAnalytics } from '@next/third-parties/google';
import clsx from 'clsx';
import ClientDiscordAuth from 'components/ClientDiscordAuth';
import type { Metadata, Viewport } from 'next';
import type { PropsWithChildren } from 'react';
import {
Expand Down Expand Up @@ -45,6 +46,7 @@ const RootLayout = (props: PropsWithChildren) => (
>
<body>
<GoogleAnalytics gaId={googleAnalyticsId} />
<ClientDiscordAuth />
<ApplicationProvider>{props.children}</ApplicationProvider>
</body>
</html>
Expand Down
37 changes: 27 additions & 10 deletions src/app/nez-perce-valley/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
'use client';

import { useEffect, useState } from 'react';
import { HerdMapOverlay } from 'components/HerdMapOverlay';
import { HuntingMapPage } from 'components/HuntingMapPage';
import { animalMarkers, genericMarkers, mapLabels } from 'config/idaho';
import { isUserLoggedIn } from 'services/discordApiService';

const NezPerceValleyPage = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);

useEffect(() => {
// Only check login status on client side
setIsLoggedIn(isUserLoggedIn());
}, []);

const NezPerceValleyPage = () => (
<HuntingMapPage
animalMarkers={animalMarkers}
genericMarkers={genericMarkers}
mapId="idaho"
mapImageSrc="/img/maps/nez_perce.jpeg"
mapLabels={mapLabels}
titleKey="POI:MAP_NAME_IDAHO"
/>
);
return (
<>
<HuntingMapPage
animalMarkers={animalMarkers}
genericMarkers={genericMarkers}
mapId="idaho"
mapImageSrc="/img/maps/nez_perce.jpeg"
mapLabels={mapLabels}
titleKey="POI:MAP_NAME_IDAHO"
/>
{isLoggedIn && <HerdMapOverlay currentMap="Nez Perce Valley" />}
</>
);
};

export default NezPerceValleyPage;
47 changes: 36 additions & 11 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
import { Error } from 'components/Error';
import { PageContent } from 'components/PageContent';
'use client';

const NotFoundPage = () => (
<>
<PageContent>
<Error status={404} />
</PageContent>
</>
);

export default NotFoundPage;
export default function NotFoundPage() {
return (
<div style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
minHeight: '100vh',
textAlign: 'center',
padding: '20px',
background: '#1a1a1a',
color: 'white'
}}>
<h1 style={{ fontSize: '72px', margin: '0' }}>404</h1>
<h2 style={{ fontSize: '24px', margin: '20px 0' }}>Page Not Found</h2>
<p style={{ fontSize: '16px', color: '#999', maxWidth: '500px' }}>
The page you're looking for doesn't exist or has been moved.
</p>
<a
href="/"
style={{
marginTop: '30px',
padding: '12px 24px',
background: '#5865F2',
color: 'white',
textDecoration: 'none',
borderRadius: '4px',
fontWeight: 'bold'
}}
>
Go Back Home
</a>
</div>
);
}
167 changes: 167 additions & 0 deletions src/components/ClientDiscordAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
'use client';

import { useEffect, useState, Suspense } from 'react';
import { useSearchParams } from 'next/navigation';
import { exchangeCodeForToken, fetchUserData, fetchUserHerds } from '@/services/discordApiService';

function DiscordAuthContent() {
const searchParams = useSearchParams();
const [user, setUser] = useState<any>(null);
const [herds, setHerds] = useState<any[]>([]);
const [loading, setLoading] = useState(false);

useEffect(() => {
const code = searchParams.get('code');
if (code && !user) {
handleDiscordCallback(code);
}

if (typeof window !== 'undefined') {
const storedToken = localStorage.getItem('discord_token');
const storedUser = localStorage.getItem('discord_user');
if (storedToken && storedUser && !user) {
setUser(JSON.parse(storedUser));
loadUserHerds();
}
}
}, [searchParams]);

const handleDiscordCallback = async (code: string) => {
setLoading(true);
try {
const tokenData = await exchangeCodeForToken(code);
if (tokenData && tokenData.access_token) {
const userData = await fetchUserData(tokenData.access_token);
if (userData) {
localStorage.setItem('discord_token', tokenData.access_token);
localStorage.setItem('discord_user', JSON.stringify(userData));
setUser(userData);
await loadUserHerds();
}
}
} catch (error) {
console.error('Discord auth error:', error);
} finally {
setLoading(false);
}
};

const loadUserHerds = async () => {
try {
const response = await fetchUserHerds();
const animals = response?.herds || response?.habitats?.flatMap(h => h.animals) || [];
setHerds(animals); // ✅ Correct - extract the array from the response
} catch (error) {
console.error('Error loading herds:', error);
}
};

const handleLogin = () => {
const clientId = process.env.NEXT_PUBLIC_DISCORD_CLIENT_ID;
const redirectUri = `${process.env.NEXT_PUBLIC_BASE_URL}/`;
const discordAuthUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=identify`;
window.location.href = discordAuthUrl;
};

const handleLogout = () => {
localStorage.removeItem('discord_token');
localStorage.removeItem('discord_user');
setUser(null);
setHerds([]);
};

return (
<div style={{
position: 'fixed',
bottom: '20px',
right: '20px',
zIndex: 9999,
display: 'flex',
flexDirection: 'column',
gap: '10px',
alignItems: 'flex-end'
}}>
{!user ? (
<button
onClick={handleLogin}
disabled={loading}
style={{
backgroundColor: '#5865F2',
color: 'white',
padding: '12px 24px',
border: 'none',
borderRadius: '8px',
fontSize: '16px',
fontWeight: 'bold',
cursor: loading ? 'not-allowed' : 'pointer',
display: 'flex',
alignItems: 'center',
gap: '8px',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.3)',
}}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0a12.64 12.64 0 0 0-.617-1.25a.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.078.078 0 0 0 .084-.028a14.09 14.09 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13.107 13.107 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10.2 10.2 0 0 0 .372-.292a.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127a12.299 12.299 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028a19.839 19.839 0 0 0 6.002-3.03a.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418z"/>
</svg>
{loading ? 'Connecting...' : 'Login with Discord'}
</button>
) : (
<div style={{
backgroundColor: 'rgba(0, 0, 0, 0.8)',
padding: '12px 16px',
borderRadius: '8px',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.3)',
maxWidth: '250px',
}}>
<div style={{
color: 'white',
fontSize: '14px',
marginBottom: '8px',
display: 'flex',
alignItems: 'center',
gap: '8px'
}}>
<img
src={`https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`}
alt="avatar"
style={{ width: '24px', height: '24px', borderRadius: '50%' }}
/>
<span style={{ fontWeight: 'bold' }}>{user.username}</span>
</div>
{herds.length > 0 && (
<div style={{
color: '#aaa',
fontSize: '12px',
marginBottom: '8px'
}}>
{herds.length} tracked animal{herds.length !== 1 ? 's' : ''}
</div>
)}
<button
onClick={handleLogout}
style={{
backgroundColor: '#ed4245',
color: 'white',
padding: '6px 12px',
border: 'none',
borderRadius: '4px',
fontSize: '12px',
cursor: 'pointer',
width: '100%',
}}
>
Logout
</button>
</div>
)}
</div>
);
}

export default function ClientDiscordAuth() {
return (
<Suspense fallback={null}>
<DiscordAuthContent />
</Suspense>
);
}
Loading