Skip to content
Closed
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
8 changes: 6 additions & 2 deletions apps/web/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ const nextConfig: NextConfig = {
},
};
}
const commonDist = path.resolve(__dirname, '../../packages/common/dist');
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, 'src'),
'@worksight/assets': path.resolve(__dirname, '../../packages/assets/dist'),
'@worksight/common': path.resolve(__dirname, '../../packages/common/dist')
}
'@worksight/common/data': path.resolve(commonDist, 'data'),
'@worksight/common/types': path.resolve(commonDist, 'types'),
'@worksight/common/utils': path.resolve(commonDist, 'utils'),
'@worksight/common': commonDist,
};
return config;
},

Expand Down
96 changes: 8 additions & 88 deletions apps/web/src/app/admin/surveys/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,103 +41,23 @@ import {
} from 'lucide-react';
import Link from 'next/link';
import { useEffect, useMemo, useState } from 'react';

interface Survey {
id: string;
title: string;
description: string;
status: 'draft' | 'active' | 'paused' | 'completed';
questionCount: number;
responseCount: number;
createdAt: string;
lastModified: string;
createdBy: string;
category: 'burnout' | 'satisfaction' | 'wellness' | 'feedback';
targetAudience: 'all' | 'managers' | 'employees' | 'specific';
}

const mockSurveys: Survey[] = [
{
id: '1',
title: 'Burnout Assessment 2025',
description: 'Comprehensive burnout evaluation for all employees',
status: 'active',
questionCount: 15,
responseCount: 247,
createdAt: '2025-01-15',
lastModified: '2025-01-20',
createdBy: 'Admin User',
category: 'burnout',
targetAudience: 'all',
},
{
id: '2',
title: 'Job Satisfaction Survey',
description: 'Quarterly job satisfaction and engagement survey',
status: 'active',
questionCount: 12,
responseCount: 156,
createdAt: '2025-01-10',
lastModified: '2025-01-18',
createdBy: 'HR Manager',
category: 'satisfaction',
targetAudience: 'employees',
},
{
id: '3',
title: 'Manager Feedback Survey',
description: 'Leadership effectiveness and team dynamics assessment',
status: 'draft',
questionCount: 8,
responseCount: 0,
createdAt: '2025-01-22',
lastModified: '2025-01-22',
createdBy: 'Admin User',
category: 'feedback',
targetAudience: 'managers',
},
{
id: '4',
title: 'Wellness Check Q4 2024',
description: 'Mental health and wellness assessment',
status: 'completed',
questionCount: 10,
responseCount: 312,
createdAt: '2024-10-01',
lastModified: '2024-12-31',
createdBy: 'Wellness Team',
category: 'wellness',
targetAudience: 'all',
},
{
id: '5',
title: 'Remote Work Experience',
description: 'Evaluation of remote work setup and productivity',
status: 'paused',
questionCount: 14,
responseCount: 89,
createdAt: '2025-01-05',
lastModified: '2025-01-19',
createdBy: 'Operations Lead',
category: 'feedback',
targetAudience: 'all',
},
];
import { getMvpSurveys, type MvpSurvey } from '@/lib/mvp-data';

function SurveyManagementContent() {
const { logout } = useAuth();
const [surveys, setSurveys] = useState<Survey[]>([]);
const [surveys, setSurveys] = useState<MvpSurvey[]>([]);
const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState<string>('all');
const [categoryFilter, setCategoryFilter] = useState<string>('all');
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
// Simulate API call
setTimeout(() => {
setSurveys(mockSurveys);
setIsLoading(false);
}, 1000);
const fixtureSurveys = getMvpSurveys();
if (fixtureSurveys.length === 0) {
throw new Error('Common survey fixtures empty; refusing silent empty fallback');
}
setSurveys(fixtureSurveys);
setIsLoading(false);
}, []);

const handleLogout = async () => {
Expand Down
101 changes: 17 additions & 84 deletions apps/web/src/app/admin/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { useAuth } from '@/auth';
import { getRoleColor, getUserRoleDisplay } from '@/auth/admin';
import { UserRole } from '@/auth/types';
import { AdminRoute } from '@/components/admin';
import { SessionTimer } from '@/components/features';
import { AppSidebar } from '@/components/main/sidebar';
Expand Down Expand Up @@ -35,6 +34,7 @@ import {
validateUserArray,
validateUserFilters,
} from '@/schemas/user';
import { getUsersWithMetrics } from '@/lib/mvp-data';
import {
AlertTriangle,
CheckCircle,
Expand All @@ -49,74 +49,6 @@ import {
} from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';

const mockUsers: UserWithMetrics[] = [
{
id: '1',
name: 'John Doe',
email: 'john.doe@company.com',
role: UserRole.EMPLOYEE,
department: 'Engineering',
team: 'Frontend',
burnoutScore: 3.2,
lastActive: '2 hours ago',
surveyCompleted: true,
riskLevel: 'low',
tasksCompleted: 24,
},
{
id: '2',
name: 'Jane Smith',
email: 'jane.smith@company.com',
role: UserRole.TEAM_LEAD,
department: 'Engineering',
team: 'Backend',
burnoutScore: 7.8,
lastActive: '30 minutes ago',
surveyCompleted: true,
riskLevel: 'high',
tasksCompleted: 31,
},
{
id: '3',
name: 'Bob Wilson',
email: 'bob.wilson@company.com',
role: UserRole.MANAGER,
department: 'Product',
team: 'Design',
burnoutScore: 5.4,
lastActive: '1 day ago',
surveyCompleted: false,
riskLevel: 'medium',
tasksCompleted: 18,
},
{
id: '4',
name: 'Alice Johnson',
email: 'alice.johnson@company.com',
role: UserRole.EMPLOYEE,
department: 'Marketing',
team: 'Content',
burnoutScore: 2.1,
lastActive: '5 minutes ago',
surveyCompleted: true,
riskLevel: 'low',
tasksCompleted: 42,
},
{
id: '5',
name: 'Charlie Brown',
email: 'charlie.brown@company.com',
role: UserRole.ADMIN,
department: 'IT',
team: 'DevOps',
burnoutScore: 6.7,
lastActive: '1 hour ago',
surveyCompleted: true,
riskLevel: 'medium',
tasksCompleted: 15,
},
];

function UserManagementContent() {
const { logout } = useAuth();
const [users, setUsers] = useState<UserWithMetrics[]>([]);
Expand All @@ -127,23 +59,24 @@ function UserManagementContent() {
const [validationErrors, setValidationErrors] = useState<string[]>([]);

useEffect(() => {
// Simulate API call with validation
setTimeout(() => {
// Validate mock data using Zod
const validationResult = validateUserArray(mockUsers);
// Load employees from @worksight/common fixtures
const fixtureUsers = getUsersWithMetrics();
const validationResult = validateUserArray(fixtureUsers);

if (!validationResult.allValid) {
const errors = validationResult.invalid.map(
(item) =>
`User at index ${item.index}: ${item.errors?.map((e: { message: string }) => e.message).join(', ')}`
);
setValidationErrors(errors);
}

if (!validationResult.allValid) {
const errors = validationResult.invalid.map(
(item) =>
`User at index ${item.index}: ${item.errors?.map((e: { message: string }) => e.message).join(', ')}`
);
setValidationErrors(errors);
}
if (validationResult.valid.length === 0 && fixtureUsers.length > 0) {
throw new Error('Common employee fixtures failed validation; refusing empty fallback');
}

// Use only valid users
setUsers(validationResult.valid.map((item) => item.data!));
setIsLoading(false);
}, 1000);
setUsers(validationResult.valid.map((item) => item.data!));
setIsLoading(false);
}, []);

// Validate filters when they change
Expand Down
88 changes: 30 additions & 58 deletions apps/web/src/app/dashboard/tasks/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import {
} from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { assignmentLookup } from '@/lib/mvp-data';
import type { Assignment } from '@worksight/common/types';

interface Task {
id: string;
Expand All @@ -68,63 +70,33 @@ interface Task {

type ViewMode = 'kanban' | 'table';

// Mock tasks data - in real app this would come from your backend
const initialTasks: Task[] = [
{
id: '1',
title: 'Implement survey results storage',
description: 'Create Zustand store for survey results with persistence',
status: 'completed',
priority: 'high',
dueDate: '2025-08-24',
storyPoints: 8,
},
{
id: '2',
title: 'Fix ESLint warnings',
description: 'Resolve remaining TypeScript and linting issues',
status: 'in-progress',
priority: 'medium',
dueDate: '2025-08-25',
storyPoints: 3,
},
{
id: '3',
title: 'Dashboard navigation improvements',
description: 'Implement client-side routing for dashboard sections',
status: 'in-progress',
priority: 'high',
dueDate: '2025-08-26',
storyPoints: 5,
},
{
id: '4',
title: 'Mobile responsive design',
description: 'Ensure dashboard works well on mobile devices',
status: 'pending',
priority: 'medium',
dueDate: '2025-08-28',
storyPoints: 13,
},
{
id: '5',
title: 'User authentication improvements',
description: 'Add password reset and email verification',
status: 'pending',
priority: 'low',
dueDate: '2025-08-30',
storyPoints: 8,
},
{
id: '6',
title: 'Add task drag and drop',
description: 'Implement kanban board with draggable tasks',
status: 'in-progress',
priority: 'high',
dueDate: '2025-08-25',
storyPoints: 8,
},
];
function mapDashboardStatus(status: Assignment['status']): Task['status'] {
if (status === 'completed') return 'completed';
if (status === 'in_progress') return 'in-progress';
return 'pending';
}

function mapDashboardPriority(priority: Assignment['priority']): Task['priority'] {
if (priority === 'critical' || priority === 'high') return 'high';
if (priority === 'medium') return 'medium';
return 'low';
}

function getInitialTasksFromCommon(): Task[] {
const assignments = assignmentLookup.all();
if (assignments.length === 0) {
throw new Error('Common assignment fixtures empty; refusing silent empty fallback');
}
return assignments.map((assignment) => ({
id: assignment.id,
title: assignment.title ?? assignment.external_id ?? 'Untitled task',
description: [assignment.epic, assignment.sprint, assignment.type].filter(Boolean).join(' · '),
status: mapDashboardStatus(assignment.status),
priority: mapDashboardPriority(assignment.priority),
dueDate: assignment.updated_at.toISOString().slice(0, 10),
storyPoints: assignment.points ?? 1,
}));
}

const statusConfig = {
pending: { icon: Clock, color: 'text-orange-500', bg: 'bg-orange-50', label: 'Pending' },
Expand All @@ -147,7 +119,7 @@ const statusOrder: Task['status'][] = ['pending', 'in-progress', 'completed'];

export default function TasksPage() {
const [viewMode, setViewMode] = useState<ViewMode>('kanban');
const [tasks, setTasks] = useState<Task[]>(initialTasks);
const [tasks, setTasks] = useState<Task[]>(() => getInitialTasksFromCommon());
const [activeTask, setActiveTask] = useState<Task | null>(null);
const [showNewTaskDialog, setShowNewTaskDialog] = useState(false);
const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
Expand Down
Loading
Loading