Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ValueProps } from '@/components/landing/ValueProps';
import { CallToAction } from '@/components/landing/CallToAction';
import { TrustBar } from '@/components/landing/TrustBar';
import { PricingCards } from '@/components/pricing/PricingCards';
import { KineticExplorer } from '@/components/landing/KineticExplorer';

export default function Home() {
return (
Expand Down
35 changes: 17 additions & 18 deletions components/mobile/MobileFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
`use client
'use client'

import React from react
import Link from next/link
import React from 'react'
import Link from 'next/link'

// Navigation links data
const footerLinks = [
{ label: Home, href: / },
{ label: About, href: /about },
{ label: Services, href: /services },
{ label: Support, href: /support },
{ label: Privacy Policy, href: /privacy },
{ label: Terms of Service, href: /terms },
{ label: Contact, href: /contact },
{ label: FAQs, href: /faq },
{ label: 'Home', href: '/' },
{ label: 'About', href: '/about' },
{ label: 'Services', href: '/services' },
{ label: 'Support', href: '/support' },
{ label: 'Privacy Policy', href: '/privacy' },
{ label: 'Terms of Service', href: '/terms' },
{ label: 'Contact', href: '/contact' },
{ label: 'FAQs', href: '/faq' },
]

// Social icons data
const socialLinks = [
{ label: Twitter, href: https://twitter.com/swiftchain, icon: 🐦 },
{ label: GitHub, href: https://github.com/swiftchain, icon: 🐙 },
{ label: LinkedIn, href: https://linkedin.com/company/swiftchain, icon: 🔗 },
{ label: Discord, href: https://discord.gg/swiftchain, icon: 💬 },
{ label: 'Twitter', href: 'https://twitter.com/swiftchain', icon: '🐦' },
{ label: 'GitHub', href: 'https://github.com/swiftchain', icon: '🐙' },
{ label: 'LinkedIn', href: 'https://linkedin.com/company/swiftchain', icon: '🔗' },
{ label: 'Discord', href: 'https://discord.gg/swiftchain', icon: '💬' },
]

export function MobileFooter() {
Expand All @@ -36,7 +36,7 @@ export function MobileFooter() {
key={link.href}
href={link.href}
className="rounded-lg px-3 py-2.5 text-sm text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 active:bg-gray-200 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:active:bg-gray-700"
style={{ minHeight: 44px }}
style={{ minHeight: '44px' }}
>
{link.label}
</Link>
Expand All @@ -53,7 +53,7 @@ export function MobileFooter() {
rel="noopener noreferrer"
className="flex h-11 w-11 items-center justify-center rounded-full text-xl transition-colors hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-100"
aria-label={social.label}
style={{ minHeight: 44px, minWidth: 44px }}
style={{ minHeight: '44px', minWidth: '44px' }}
>
<span className="sr-only">{social.label}</span>
<span role="img" aria-hidden="true">
Expand All @@ -73,4 +73,3 @@ export function MobileFooter() {
}

export default MobileFooter

43 changes: 26 additions & 17 deletions hooks/useDriverReputation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,26 @@ export interface UseDriverReputationResult {
* state on an unmounted component.
*/
export function useDriverReputation(driverId: string): UseDriverReputationResult {
const [onChainScore, setOnChainScore] = useState<number | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
// Store the settled result together with the driverId it belongs to, so
// loading is derived from a stale/absent result rather than written back
// into state from the effect.
const [result, setResult] = useState<{
driverId: string;
onChainScore: number | null;
error: string | null;
} | null>(null);

useEffect(() => {
if (!driverId) {
setOnChainScore(null);
setIsLoading(false);
return;
}
if (!driverId) return;

const controller = new AbortController();
let cancelled = false;

setIsLoading(true);

reputationService
.getDriverReputation(driverId, controller.signal)
.then((data) => {
if (cancelled) return;
setOnChainScore(data.onChainScore);
setError(null);
setResult({ driverId, onChainScore: data.onChainScore, error: null });
})
.catch((err: unknown) => {
if (cancelled) return;
Expand All @@ -48,10 +46,7 @@ export function useDriverReputation(driverId: string): UseDriverReputationResult
err instanceof Error && err.message
? err.message
: 'Failed to load on-chain reputation';
setError(message);
})
.finally(() => {
if (!cancelled) setIsLoading(false);
setResult({ driverId, onChainScore: null, error: message });
});

return () => {
Expand All @@ -60,5 +55,19 @@ export function useDriverReputation(driverId: string): UseDriverReputationResult
};
}, [driverId]);

return { onChainScore, isLoading, error };
// With no driverId there is nothing to fetch.
if (!driverId) {
return { onChainScore: null, isLoading: false, error: null };
}

// No result yet for this driverId means the request is still in flight.
if (!result || result.driverId !== driverId) {
return { onChainScore: null, isLoading: true, error: null };
}

return {
onChainScore: result.onChainScore,
isLoading: false,
error: result.error,
};
}
25 changes: 14 additions & 11 deletions hooks/useTheme.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
// hooks/useTheme.ts

import { useState, useEffect } from 'react';
import { useState, useEffect, useCallback } from 'react';
import { ThemeService, Theme } from '@/services/themeService';

export const useTheme = (userId?: string) => {
const [theme, setThemeState] = useState<Theme>('system');

const updateTheme = useCallback(
(newTheme: Theme) => {
setThemeState(newTheme);
ThemeService.setThemeToStorage(newTheme);

if (userId) {
ThemeService.syncThemeToAPI(userId, newTheme).catch(console.error);
}
},
[userId]
);

useEffect(() => {
const initializeTheme = async () => {
// 1. Sync from local storage immediately to match the blocking script
Expand All @@ -27,7 +39,7 @@ export const useTheme = (userId?: string) => {
}
};
initializeTheme();
}, [userId]);
}, [userId, updateTheme]);

// Apply theme to DOM when state changes
useEffect(() => {
Expand Down Expand Up @@ -60,14 +72,5 @@ export const useTheme = (userId?: string) => {
return () => mediaQuery.removeEventListener('change', handleChange);
}, [theme]);

const updateTheme = (newTheme: Theme) => {
setThemeState(newTheme);
ThemeService.setThemeToStorage(newTheme);

if (userId) {
ThemeService.syncThemeToAPI(userId, newTheme).catch(console.error);
}
};

return { theme, setTheme: updateTheme };
};
Loading