Due Date
-
{card.due ? formatDate(card.due) : 'No due date'}
+
{card.due ? formatDateTime(card.due) : 'No due date'}
Position
diff --git a/frontend/src/components/ProtectedRoute.tsx b/frontend/src/components/ProtectedRoute.tsx
index c0868f1..e4a7f23 100644
--- a/frontend/src/components/ProtectedRoute.tsx
+++ b/frontend/src/components/ProtectedRoute.tsx
@@ -1,4 +1,4 @@
-import { Navigate } from 'react-router-dom';
+import { Navigate, useLocation } from 'react-router-dom';
import { useApp } from '../context/AppContext';
interface ProtectedRouteProps {
@@ -7,6 +7,7 @@ interface ProtectedRouteProps {
export function ProtectedRoute({ children }: ProtectedRouteProps) {
const { token, loading } = useApp();
+ const location = useLocation();
if (loading) {
return (
@@ -17,7 +18,8 @@ export function ProtectedRoute({ children }: ProtectedRouteProps) {
}
if (!token) {
- return
;
+ // Pass the current location as a redirect query parameter
+ return
;
}
return <>{children}>;
diff --git a/frontend/src/components/icons/ChevronDownIcon.tsx b/frontend/src/components/icons/ChevronDownIcon.tsx
new file mode 100644
index 0000000..599348d
--- /dev/null
+++ b/frontend/src/components/icons/ChevronDownIcon.tsx
@@ -0,0 +1,17 @@
+const ChevronDownIcon = () => (
+
+);
+
+export default ChevronDownIcon;
diff --git a/frontend/src/components/kanban/BoardCard.tsx b/frontend/src/components/kanban/BoardCard.tsx
index 7445d9a..7ee6c13 100644
--- a/frontend/src/components/kanban/BoardCard.tsx
+++ b/frontend/src/components/kanban/BoardCard.tsx
@@ -1,5 +1,6 @@
import { Board } from '../../types/kanban';
-import { Link, useNavigate } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { formatRelativeTime } from '../../utils/dateFormat';
interface BoardCardProps {
board: Board;
@@ -7,92 +8,73 @@ interface BoardCardProps {
}
export function BoardCard({ board, onDelete }: BoardCardProps) {
- const navigate = useNavigate();
-
const handleDelete = (e: React.MouseEvent) => {
e.preventDefault();
- e.stopPropagation();
if (window.confirm(`Are you sure you want to delete "${board.name}"?`)) {
onDelete(board.id);
}
};
- const formatDate = (dateString: string) => {
- const date = new Date(dateString);
- const now = new Date();
- const diffMs = now.getTime() - date.getTime();
- const diffMins = Math.floor(diffMs / 60000);
- const diffHours = Math.floor(diffMs / 3600000);
- const diffDays = Math.floor(diffMs / 86400000);
-
- if (diffMins < 1) return 'Just now';
- if (diffMins < 60) return `${diffMins}m ago`;
- if (diffHours < 24) return `${diffHours}h ago`;
- if (diffDays < 7) return `${diffDays}d ago`;
- return date.toLocaleDateString();
- };
-
return (
-
navigate(`/boards/${board.id}`)} className="block group cursor-pointer">
-
-
-
+
+
+
+
{board.name}
-
-
-
e.stopPropagation()}
- className="text-gray-400 hover:text-blue-400 transition-colors"
- title="Edit board"
+
+
+
+
+
+
+
-
+
+
+
+
+
- {board.description && (
-
{board.description}
- )}
+ {board.description && (
+
{board.description}
+ )}
-
-
- Last activity: {formatDate(board.date_last_activity)}
-
-
+
+
+ Last activity: {formatRelativeTime(board.date_last_activity)}
+
);
diff --git a/frontend/src/components/kanban/KanbanColumn.tsx b/frontend/src/components/kanban/KanbanColumn.tsx
index 1cbca5b..5cce0c7 100644
--- a/frontend/src/components/kanban/KanbanColumn.tsx
+++ b/frontend/src/components/kanban/KanbanColumn.tsx
@@ -68,7 +68,7 @@ export function KanbanColumn({
};
return (
-
+
@@ -133,7 +133,7 @@ export function KanbanColumn({
>
{cards.map((card) => (
onOpenCardModal(card)} />
diff --git a/frontend/src/context/AppContext.tsx b/frontend/src/context/AppContext.tsx
index 6fc794f..25d4c2a 100644
--- a/frontend/src/context/AppContext.tsx
+++ b/frontend/src/context/AppContext.tsx
@@ -1,19 +1,12 @@
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
-import { User, CartItem } from '../types';
+import { User } from '../types';
interface AppContextValue {
user: User | null;
token: string | null;
- cart: CartItem[];
loading: boolean;
login: (userData: User, authToken: string) => void;
logout: () => void;
- addToCart: (product: CartItem) => void;
- removeFromCart: (productId: number) => void;
- updateCartQuantity: (productId: number, quantity: number) => void;
- clearCart: () => void;
- cartTotal: number;
- cartItemCount: number;
}
interface AppProviderProps {
@@ -29,7 +22,7 @@ export { AppContext };
export function AppProvider({ children }: AppProviderProps) {
const [user, setUser] = useState(null);
const [token, setToken] = useState(null);
- const [cart, setCart] = useState([]);
+ const [cart, setCart] = useState([]);
const [loading, setLoading] = useState(true);
// Load user and token from localStorage on mount
@@ -82,58 +75,14 @@ export function AppProvider({ children }: AppProviderProps) {
setCart([]);
};
- const addToCart = (product: CartItem) => {
- setCart((prevCart: CartItem[]) => {
- const existingItem = prevCart.find((item) => item.id === product.id);
- if (existingItem) {
- return prevCart.map((item) =>
- item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
- );
- }
- return [...prevCart, { ...product, quantity: 1 }];
- });
- };
-
- const removeFromCart = (productId: number) => {
- setCart((prevCart: CartItem[]) => prevCart.filter((item) => item.id !== productId));
- };
-
- const updateCartQuantity = (productId: number, quantity: number) => {
- if (quantity <= 0) {
- removeFromCart(productId);
- return;
- }
- setCart((prevCart: CartItem[]) =>
- prevCart.map((item) => (item.id === productId ? { ...item, quantity } : item))
- );
- };
-
- const clearCart = () => {
- setCart([]);
- };
-
- const cartTotal = cart.reduce(
- (total: number, item: CartItem) => total + item.price * item.quantity,
- 0
- );
-
- const cartItemCount = cart.reduce((total: number, item: CartItem) => total + item.quantity, 0);
-
return (
{children}
diff --git a/frontend/src/hooks/useApi.ts b/frontend/src/hooks/useApi.ts
index 8b6c90c..fa54de6 100644
--- a/frontend/src/hooks/useApi.ts
+++ b/frontend/src/hooks/useApi.ts
@@ -42,7 +42,8 @@ api.interceptors.response.use(
localStorage.removeItem('user');
if (!['/login', '/register'].includes(window.location.pathname)) {
- window.location.href = '/login';
+ const currentPath = window.location.pathname;
+ window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`;
}
}
return Promise.reject(error);
diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts
index acdcc07..c962cdb 100644
--- a/frontend/src/hooks/useAuth.ts
+++ b/frontend/src/hooks/useAuth.ts
@@ -12,7 +12,7 @@ export function useAuth() {
const { withLoader } = useLoader();
const { addNotification } = useToast();
- const handleLogin = async (email: string, password: string) => {
+ const handleLogin = async (email: string, password: string, redirectPath?: string | null) => {
try {
const response = await withLoader(() => loginApi(email, password), 'Logging in...');
@@ -38,8 +38,9 @@ export function useAuth() {
duration: 3000,
});
- // Navigate to boards
- navigate('/boards');
+ // Navigate to the redirect path from query parameter or default to /boards
+ const redirectTo = redirectPath || '/boards';
+ navigate(redirectTo);
return user;
} catch (err: any) {
diff --git a/frontend/src/pages/CardDetail.tsx b/frontend/src/pages/CardDetail.tsx
index 2f07c02..72a576a 100644
--- a/frontend/src/pages/CardDetail.tsx
+++ b/frontend/src/pages/CardDetail.tsx
@@ -17,6 +17,7 @@ import Trash2Icon from '../components/icons/Trash2Icon';
import ArrowLeftIcon from '../components/icons/ArrowLeftIcon';
import Edit2Icon from '../components/icons/Edit2Icon';
import { NarrowPageLayout } from '@/components/NarrowPageLayout';
+import { formatDateTime } from '../utils/dateFormat';
export function CardDetail() {
const { id: boardId, cardId } = useParams<{ id: string; cardId: string }>();
@@ -76,16 +77,6 @@ export function CardDetail() {
return null;
}
- const formatDate = (dateString: string) => {
- return new Date(dateString).toLocaleDateString('en-US', {
- year: 'numeric',
- month: 'short',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit',
- });
- };
-
return (
@@ -112,7 +103,7 @@ export function CardDetail() {
- In list • Created {formatDate(card.created_at)}
+ In list • Created {formatDateTime(card.created_at)}