Skip to content
Draft
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
23 changes: 21 additions & 2 deletions src/components/settings/SettingsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
import { Card } from '@/components/ui';
import { bcClient } from '@/services/bc/bcClient';
import { useAuth } from '@/services/auth';
import { useSettingsStore } from '@/hooks/useSettingsStore';
import {
BuildingOffice2Icon,
EnvelopeIcon,
Expand All @@ -26,6 +27,7 @@ interface CompanyInfo {

export function SettingsPanel() {
const { account } = useAuth();
const { weeklyHoursTarget, notificationsEnabled, updateSettings } = useSettingsStore();
const [companyInfo, setCompanyInfo] = useState<CompanyInfo | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
Expand Down Expand Up @@ -135,8 +137,19 @@ export function SettingsPanel() {
<p className="text-sm text-dark-400">Your target hours per week for tracking</p>
</div>
<input
id="weekly-hours-target"
type="number"
defaultValue={40}
min={0}
max={168}
value={weeklyHoursTarget}
onChange={(e) => {
const parsed = parseFloat(e.target.value);
const safeValue = isNaN(parsed) ? 0 : parsed;
updateSettings({
weeklyHoursTarget: Math.min(168, Math.max(0, safeValue)),
});
}}
aria-label="Weekly hours target"
className="w-20 rounded-lg border border-dark-600 bg-dark-800 px-3 py-2 text-dark-100 focus:outline-none focus:ring-2 focus:ring-thyme-500"
/>
</div>
Expand All @@ -146,7 +159,13 @@ export function SettingsPanel() {
<p className="text-sm text-dark-400">Get reminded to fill in your timesheet</p>
</div>
<label className="relative inline-flex cursor-pointer items-center">
<input type="checkbox" defaultChecked className="peer sr-only" />
<input
type="checkbox"
checked={notificationsEnabled}
onChange={(e) => updateSettings({ notificationsEnabled: e.target.checked })}
className="peer sr-only"
aria-label="Timesheet reminders"
/>
<div className="peer h-6 w-11 rounded-full bg-dark-600 after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:transition-all after:content-[''] peer-checked:bg-thyme-600 peer-checked:after:translate-x-full peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-thyme-500"></div>
</label>
</div>
Expand Down
22 changes: 14 additions & 8 deletions src/components/team/TeamList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use client';

import { useState, useEffect } from 'react';
import { useState, useEffect, useMemo } from 'react';
import { TeamMemberCard } from './TeamMemberCard';
import { Card } from '@/components/ui';
import { bcClient } from '@/services/bc/bcClient';
import { useSettingsStore } from '@/hooks/useSettingsStore';
import type { BCEmployee } from '@/types';

interface TeamMember {
Expand All @@ -16,13 +17,12 @@ interface TeamMember {
status: 'on-track' | 'behind' | 'ahead';
}

function mapEmployeeToMember(employee: BCEmployee): TeamMember {
function mapEmployeeToMember(employee: BCEmployee, hoursTarget: number): TeamMember {
// TODO: Fetch actual hours from timeRegistrationEntries
const hoursThisWeek = 0;
const hoursTarget = 40;

let status: 'on-track' | 'behind' | 'ahead' = 'on-track';
const progress = hoursThisWeek / hoursTarget;
const progress = hoursTarget > 0 ? hoursThisWeek / hoursTarget : 0;
if (progress < 0.6) status = 'behind';
else if (progress > 1) status = 'ahead';

Expand All @@ -38,16 +38,16 @@ function mapEmployeeToMember(employee: BCEmployee): TeamMember {
}

export function TeamList() {
const { weeklyHoursTarget } = useSettingsStore();
const [isLoading, setIsLoading] = useState(true);
const [members, setMembers] = useState<TeamMember[]>([]);
const [employees, setEmployees] = useState<BCEmployee[]>([]);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
async function fetchEmployees() {
try {
const employees = await bcClient.getEmployees("status eq 'Active'");
const teamMembers = employees.map(mapEmployeeToMember);
setMembers(teamMembers);
const data = await bcClient.getEmployees("status eq 'Active'");
setEmployees(data);
} catch (err) {
console.error('Failed to fetch employees:', err);
setError('Failed to load team members');
Expand All @@ -58,6 +58,12 @@ export function TeamList() {
fetchEmployees();
}, []);

// Derive members from employees when weeklyHoursTarget changes (no API refetch)
const members = useMemo(
() => employees.map((emp) => mapEmployeeToMember(emp, weeklyHoursTarget)),
[employees, weeklyHoursTarget]
);

const totalHours = members.reduce((sum, m) => sum + m.hoursThisWeek, 0);
const totalTarget = members.reduce((sum, m) => sum + m.hoursTarget, 0);
const behindCount = members.filter((m) => m.status === 'behind').length;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface SettingsStore extends UserSettings {
const defaultSettings: UserSettings = {
defaultProjectId: undefined,
defaultTaskId: undefined,
weeklyHoursTarget: 40,
weeklyHoursTarget: 37.5,
notificationsEnabled: true,
theme: 'system',
};
Expand Down