feat: Implement browser-compatible processing pipeline for student requests

- Added SimpleBrowserProcessor class to handle student requests in a queue.
- Introduced methods for adding requests, notifying subscribers, and processing the queue.
- Mock AI matching logic implemented to simulate resource matching based on request categories and urgency.
- Added generateInsights method to analyze request trends and urgencies.

feat: Create authentication context for user management

- Developed AuthContext to manage user authentication state.
- Implemented login and logout functionalities with mock user data.
- Added loading state management during authentication processes.

feat: Add notification context for managing user notifications

- Created NotificationContext to handle notifications throughout the application.
- Implemented methods for adding, marking as read, and removing notifications.

feat: Introduce common hooks for utility functions

- Developed useHashRoute for hash-based routing.
- Created useLocalStorage for managing local storage with TypeScript support.
- Implemented useMediaQuery for responsive design handling.
- Added useDebounce for debouncing values in state.

feat: Implement donation impact calculation hook

- Created useDonationImpact hook to calculate the impact of donations.
- Added useFormValidation hook for form state management and validation.

feat: Design main layout and page structure components

- Developed MainLayout and PageShell components for consistent layout structure.
- Created SectionHeader and Card components for reusable UI elements.

feat: Build HomePage with impact statistics and service offerings

- Implemented HomePage component with hero section, impact stats, and service cards.
- Integrated tracking for donation and volunteer actions.

feat: Add analytics utilities for tracking events

- Created analytics utility for tracking page views and custom events.
- Implemented donation and volunteer tracking functionalities.

feat: Enhance helper functions for various utilities

- Developed utility functions for impact calculation, formatting, validation, and debouncing.
This commit is contained in:
defiQUG
2025-10-05 08:59:50 -07:00
parent e6aec40163
commit ad8e763750
20 changed files with 3398 additions and 1689 deletions
+84
View File
@@ -0,0 +1,84 @@
import { useState, useEffect } from 'react'
// Hash-based routing hook
export const useHashRoute = () => {
const parseRoute = (): string => window.location.hash?.slice(1) || "/"
const [route, setRoute] = useState<string>(parseRoute())
useEffect(() => {
const handleHashChange = (): void => setRoute(parseRoute())
window.addEventListener("hashchange", handleHashChange)
return () => window.removeEventListener("hashchange", handleHashChange)
}, [])
const navigate = (newRoute: string): void => {
window.location.hash = newRoute
}
return { route, navigate }
}
// Local storage hook with TypeScript support
export const useLocalStorage = <T>(key: string, initialValue: T) => {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error)
return initialValue
}
})
const setValue = (value: T | ((val: T) => T)): void => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value
setStoredValue(valueToStore)
window.localStorage.setItem(key, JSON.stringify(valueToStore))
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error)
}
}
return [storedValue, setValue] as const
}
// Media query hook
export const useMediaQuery = (query: string): boolean => {
const [matches, setMatches] = useState<boolean>(false)
useEffect(() => {
const media = window.matchMedia(query)
if (media.matches !== matches) {
setMatches(media.matches)
}
const listener = (event: MediaQueryListEvent): void => {
setMatches(event.matches)
}
media.addEventListener('change', listener)
return () => media.removeEventListener('change', listener)
}, [matches, query])
return matches
}
// Debounce hook
export const useDebounce = <T>(value: T, delay: number): T => {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value)
}, delay)
return () => {
clearTimeout(handler)
}
}, [value, delay])
return debouncedValue
}
+108
View File
@@ -0,0 +1,108 @@
import { useState, useEffect } from 'react'
// Types
export interface ImpactCalculation {
students: number
families: number
backpacks: number
clothing: number
emergency: number
annual: {
students: number
families: number
totalImpact: string
}
}
// Custom hook for donation impact calculations
export const useDonationImpact = (amount: number): ImpactCalculation => {
const [impact, setImpact] = useState<ImpactCalculation>({
students: 0,
families: 0,
backpacks: 0,
clothing: 0,
emergency: 0,
annual: {
students: 0,
families: 0,
totalImpact: '0 students supported annually'
}
})
useEffect(() => {
const calculateImpact = (donationAmount: number): ImpactCalculation => {
const students = Math.floor(donationAmount / 25) // $25 per student for basic supplies
const families = Math.floor(donationAmount / 50) // $50 per family for comprehensive support
const backpacks = Math.floor(donationAmount / 30) // $30 for complete backpack kit
const clothing = Math.floor(donationAmount / 45) // $45 for clothing items
const emergency = Math.floor(donationAmount / 75) // $75 for emergency assistance
return {
students,
families,
backpacks,
clothing,
emergency,
annual: {
students: Math.floor((donationAmount * 12) / 25),
families: Math.floor((donationAmount * 12) / 50),
totalImpact: `${Math.floor((donationAmount * 12) / 25)} students supported annually`
}
}
}
setImpact(calculateImpact(amount))
}, [amount])
return impact
}
// Hook for form validation
export const useFormValidation = <T extends Record<string, any>>(
initialValues: T,
validationRules: Record<keyof T, (value: any) => string | null>
) => {
const [values, setValues] = useState<T>(initialValues)
const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({})
const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({})
const validate = (fieldName?: keyof T): boolean => {
const fieldsToValidate = fieldName ? [fieldName] : Object.keys(validationRules) as (keyof T)[]
const newErrors: Partial<Record<keyof T, string>> = { ...errors }
let isValid = true
fieldsToValidate.forEach((field) => {
const error = validationRules[field](values[field])
if (error) {
newErrors[field] = error
isValid = false
} else {
delete newErrors[field]
}
})
setErrors(newErrors)
return isValid
}
const setValue = (fieldName: keyof T, value: any): void => {
setValues(prev => ({ ...prev, [fieldName]: value }))
setTouched(prev => ({ ...prev, [fieldName]: true }))
}
const resetForm = (): void => {
setValues(initialValues)
setErrors({})
setTouched({})
}
return {
values,
errors,
touched,
setValue,
validate,
resetForm,
isValid: Object.keys(errors).length === 0
}
}