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
13 changes: 7 additions & 6 deletions web/App.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react';
import { HashRouter, Routes, Route, Navigate } from 'react-router-dom';
import { HashRouter, Navigate, Route, Routes } from 'react-router-dom';
import { Layout } from './components/layout/Layout';
import { ThemeWrapper } from './components/layout/ThemeWrapper';
import { AuthProvider, useAuth } from './contexts/AuthContext';
import { ThemeProvider } from './contexts/ThemeContext';
import { Auth } from './pages/Auth';
import { Dashboard } from './pages/Dashboard';
import { Groups } from './pages/Groups';
import { GroupDetails } from './pages/GroupDetails';
import { Friends } from './pages/Friends';
import { Layout } from './components/layout/Layout';
import { ThemeWrapper } from './components/layout/ThemeWrapper';
import { GroupDetails } from './pages/GroupDetails';
import { Groups } from './pages/Groups';
import { Profile } from './pages/Profile';

// Protected Route Wrapper
const ProtectedRoute = ({ children }: { children: React.ReactElement }) => {
Expand All @@ -35,7 +36,7 @@ const AppRoutes = () => {
<Route path="/groups" element={<ProtectedRoute><Groups /></ProtectedRoute>} />
<Route path="/groups/:id" element={<ProtectedRoute><GroupDetails /></ProtectedRoute>} />
<Route path="/friends" element={<ProtectedRoute><Friends /></ProtectedRoute>} />
<Route path="/profile" element={<ProtectedRoute><div className="p-8 text-center text-xl">Profile Management Coming Soon</div></ProtectedRoute>} />
<Route path="/profile" element={<ProtectedRoute><Profile /></ProtectedRoute>} />

<Route path="*" element={<Navigate to={isAuthenticated ? "/dashboard" : "/login"} />} />
</Routes>
Expand Down
17 changes: 10 additions & 7 deletions web/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React from 'react';
import { CreditCard, Layers, LayoutDashboard, LogOut, Moon, Sun, UserCircle, Users } from 'lucide-react';
import { Link, useLocation } from 'react-router-dom';
import { useTheme } from '../../contexts/ThemeContext';
import { useAuth } from '../../contexts/AuthContext';
import { THEMES } from '../../constants';
import { LayoutDashboard, Users, UserCircle, LogOut, Sun, Moon, Layers, CreditCard, UserPlus } from 'lucide-react';
import { useAuth } from '../../contexts/AuthContext';
import { useTheme } from '../../contexts/ThemeContext';
import { Button } from '../ui/Button';

export const Sidebar = () => {
Expand Down Expand Up @@ -56,9 +55,13 @@ export const Sidebar = () => {
<div className="mt-auto flex flex-col gap-4">
{user && (
<div className={`p-4 flex items-center gap-3 ${style === THEMES.NEOBRUTALISM ? 'border-2 border-black bg-white text-black' : 'rounded-xl bg-black/20 text-white'}`}>
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-yellow-400 to-orange-500 flex items-center justify-center font-bold text-white">
{user.name.charAt(0)}
</div>
{user.imageUrl && /^(https?:|data:image)/.test(user.imageUrl) ? (
<img src={user.imageUrl} alt={user.name} className="w-8 h-8 rounded-full object-cover" />
) : (
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-yellow-400 to-orange-500 flex items-center justify-center font-bold text-white">
{user.name.charAt(0)}
</div>
)}
<div className="flex-1 overflow-hidden">
<p className="font-bold truncate">{user.name}</p>
</div>
Expand Down
24 changes: 12 additions & 12 deletions web/components/ui/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React from 'react';
import { useTheme } from '../../contexts/ThemeContext';
import { THEMES } from '../../constants';
import { useTheme } from '../../contexts/ThemeContext';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
size?: 'sm' | 'md' | 'lg';
}

export const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'md',
className = '',
...props
export const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'md',
className = '',
...props
}) => {
const { style } = useTheme();

const baseStyles = "transition-all duration-200 font-bold flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed";

const sizeStyles = {
sm: "px-3 py-1.5 text-sm",
md: "px-5 py-2.5 text-base",
Expand All @@ -27,8 +27,8 @@ export const Button: React.FC<ButtonProps> = ({
let themeStyles = "";

if (style === THEMES.NEOBRUTALISM) {
themeStyles = "border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] active:translate-x-[4px] active:translate-y-[4px] active:shadow-none rounded-none uppercase tracking-wider";
themeStyles = "border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] active:translate-x-[4px] active:translate-y-[4px] active:shadow-none rounded-none uppercase tracking-wider font-mono";

if (variant === 'primary') themeStyles += " bg-neo-main text-white";
if (variant === 'secondary') themeStyles += " bg-neo-second text-black";
if (variant === 'danger') themeStyles += " bg-red-500 text-white";
Expand All @@ -37,15 +37,15 @@ export const Button: React.FC<ButtonProps> = ({
} else {
// Glassmorphism
themeStyles = "rounded-xl backdrop-blur-md border border-white/20 shadow-lg hover:shadow-xl active:scale-95";

if (variant === 'primary') themeStyles += " bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-blue-500/30";
if (variant === 'secondary') themeStyles += " bg-white/10 text-white hover:bg-white/20";
if (variant === 'danger') themeStyles += " bg-gradient-to-r from-red-500 to-pink-600 text-white shadow-red-500/30";
if (variant === 'ghost') themeStyles += " bg-transparent border-none shadow-none hover:bg-white/10 text-current";
}

return (
<button
<button
className={`${baseStyles} ${sizeStyles[size]} ${themeStyles} ${className}`}
{...props}
>
Expand Down
26 changes: 13 additions & 13 deletions web/components/ui/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { AnimatePresence, motion, Variants } from 'framer-motion';
import { X } from 'lucide-react';
import React from 'react';
import { motion, AnimatePresence, Variants } from 'framer-motion';
import { useTheme } from '../../contexts/ThemeContext';
import { THEMES } from '../../constants';
import { X } from 'lucide-react';
import { useTheme } from '../../contexts/ThemeContext';

interface ModalProps {
isOpen: boolean;
Expand All @@ -22,20 +22,20 @@ export const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children,

const modalVariants: Variants = style === THEMES.NEOBRUTALISM ? {
hidden: { y: '100%', rotate: -5, opacity: 0 },
visible: {
y: 0,
rotate: 0,
visible: {
y: 0,
rotate: 0,
opacity: 1,
transition: { type: 'spring', damping: 15, stiffness: 200 }
transition: { type: 'spring', damping: 15, stiffness: 200 }
},
exit: { y: '100%', rotate: 5, opacity: 0 }
} : {
hidden: { scale: 0.8, opacity: 0, backdropFilter: 'blur(0px)' },
visible: {
scale: 1,
opacity: 1,
visible: {
scale: 1,
opacity: 1,
backdropFilter: 'blur(10px)',
transition: { type: 'spring', damping: 20, stiffness: 300 }
transition: { type: 'spring', damping: 20, stiffness: 300 }
},
exit: { scale: 0.8, opacity: 0 }
};
Expand All @@ -58,8 +58,8 @@ export const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children,
animate="visible"
exit="exit"
className={`relative w-full max-w-lg overflow-hidden flex flex-col max-h-[90vh]
${style === THEMES.NEOBRUTALISM
? 'bg-white border-2 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)]'
${style === THEMES.NEOBRUTALISM
? 'bg-white border-2 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] rounded-none'
: 'bg-gray-900/80 border border-white/20 rounded-3xl shadow-2xl text-white'}`}
>
{/* Header */}
Expand Down
11 changes: 8 additions & 3 deletions web/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { User } from '../types';
import { createContext, ReactNode, useContext, useEffect, useState } from 'react';
import { getProfile } from '../services/api';
import { User } from '../types';

interface AuthContextType {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
login: (token: string, user: User) => void;
logout: () => void;
updateUserInContext: (userData: User) => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);
Expand Down Expand Up @@ -47,8 +48,12 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
setUser(null);
};

const updateUserInContext = (userData: User) => {
setUser(userData);
};

return (
<AuthContext.Provider value={{ user, isAuthenticated: !!user, isLoading, login, logout }}>
<AuthContext.Provider value={{ user, isAuthenticated: !!user, isLoading, login, logout, updateUserInContext }}>
{children}
</AuthContext.Provider>
);
Expand Down
Loading
Loading