diff --git a/package.json b/package.json
index f6560a3..f246fba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "thesisflow",
- "version": "5.7.1",
+ "version": "5.7.5",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/src/components/ExpertRequests/ExpertRequestsPage.tsx b/src/components/ExpertRequests/ExpertRequestsPage.tsx
index 30d67ce..df083da 100644
--- a/src/components/ExpertRequests/ExpertRequestsPage.tsx
+++ b/src/components/ExpertRequests/ExpertRequestsPage.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import {
Alert, Box, Button, Card, CardActions, CardContent, Chip,
- Divider, LinearProgress, Paper, Skeleton, Stack, TextField, Typography
+ Divider, LinearProgress, Paper, Skeleton, Stack, TextField, Tooltip, Typography
} from '@mui/material';
import { Edit as EditIcon } from '@mui/icons-material';
import { useNavigate } from 'react-router-dom';
@@ -438,6 +438,26 @@ export default function ExpertRequestsPage({ role, roleLabel, allowedRoles }: Ex
navigate(`${basePath}/${requestToOpen.groupId}`, { state: { expertRequest: requestToOpen } });
}, [navigate, role]);
+ // Check if adviser has all skills properly rated (rating > 0)
+ // Advisers must rate their skills before they can edit slots
+ const allSkillsRated = React.useMemo(() => {
+ // Only advisers need to rate skills before editing slots
+ if (role !== 'adviser') return true;
+ // If no department skills exist, allow editing
+ if (departmentSkills.length === 0) return true;
+ // Check if all department skills have a rating > 0
+ return departmentSkills.every((skill) => {
+ const userRating = skillRatings.find((r) => r.skillId === skill.id);
+ return userRating && userRating.rating > 0;
+ });
+ }, [role, departmentSkills, skillRatings]);
+
+ const editSlotsDisabledReason = !expertProfile
+ ? 'Loading profile...'
+ : !allSkillsRated
+ ? 'Rate all your skills first before editing slots'
+ : undefined;
+
if (!viewerRole && session?.loading) {
return (
@@ -657,14 +677,21 @@ export default function ExpertRequestsPage({ role, roleLabel, allowedRoles }: Ex
) : (
-
+
+
+
+
{expertUid && (
- {/* Skill ratings card */}
-
-
-
-
- Your Skills
-
- {departmentSkills.length > 0 && (
- r.rating > 0).length}/${departmentSkills.length}`}
- size="small"
- color={
- skillRatings.filter((r) => r.rating > 0).length === departmentSkills.length
- ? 'success'
- : 'warning'
- }
- variant="outlined"
- />
- )}
-
- {skillsLoading ? (
-
-
-
-
-
- ) : departmentSkills.length === 0 ? (
-
- No skill templates defined for your department yet.
-
- ) : (
-
- {/* Show skill overview with ratings */}
- {departmentSkills.slice(0, 5).map((skill) => {
- const userRating = skillRatings.find((r) => r.skillId === skill.id);
- const rating = userRating?.rating ?? 0;
- return (
-
-
-
- {skill.name}
-
- 0 ? 'text.primary' : 'text.disabled'}
- >
- {rating > 0 ? `${rating}/10` : '—'}
-
-
-
-
- );
- })}
- {departmentSkills.length > 5 && (
-
- +{departmentSkills.length - 5} more skills
-
+ {/* Skill ratings card - only for advisers */}
+ {role === 'adviser' && (
+
+
+
+
+ Your Skills
+
+ {departmentSkills.length > 0 && (
+ r.rating > 0).length}/${departmentSkills.length}`}
+ size="small"
+ color={
+ skillRatings.filter((r) => r.rating > 0).length === departmentSkills.length
+ ? 'success'
+ : 'warning'
+ }
+ variant="outlined"
+ />
)}
+ {skillsLoading ? (
+
+
+
+
+
+ ) : departmentSkills.length === 0 ? (
+
+ No skill templates defined for your department yet.
+
+ ) : (
+
+ {/* Show skill overview with ratings */}
+ {departmentSkills.slice(0, 5).map((skill) => {
+ const userRating = skillRatings.find((r) => r.skillId === skill.id);
+ // Show 0 if rating is <= 0 (initial rating is -1)
+ const rawRating = userRating?.rating ?? -1;
+ const displayRating = rawRating <= 0 ? 0 : rawRating;
+ const hasValidRating = rawRating > 0;
+ return (
+
+
+
+ {skill.name}
+
+
+ {hasValidRating ? `${displayRating}/10` : `${displayRating}/10`}
+
+
+
+
+ );
+ })}
+ {departmentSkills.length > 5 && (
+
+ +{departmentSkills.length - 5} more skills
+
+ )}
+
+ )}
+
+ {departmentSkills.length > 0 && (
+
+ }
+ onClick={() => setSkillDialogOpen(true)}
+ fullWidth
+ >
+ Edit Skills
+
+
)}
-
- {departmentSkills.length > 0 && (
-
- }
- onClick={() => setSkillDialogOpen(true)}
- fullWidth
- >
- Edit Skills
-
-
- )}
-
+
+ )}
diff --git a/src/components/MentorRequests/MentorRequestsPage.tsx b/src/components/MentorRequests/MentorRequestsPage.tsx
deleted file mode 100644
index d57c6e5..0000000
--- a/src/components/MentorRequests/MentorRequestsPage.tsx
+++ /dev/null
@@ -1,597 +0,0 @@
-import * as React from 'react';
-import {
- Alert, Box, Button, Card, CardActions, CardContent,
- Paper, Skeleton, Stack, TextField, Typography,
-} from '@mui/material';
-import { useNavigate } from 'react-router-dom';
-import { useSession } from '@toolpad/core';
-import type { ExpertRequest, ExpertRequestRole } from '../../types/expertRequest';
-import type { ThesisGroup } from '../../types/group';
-import type { Session } from '../../types/session';
-import type { UserProfile, UserRole } from '../../types/profile';
-import { DEFAULT_MAX_EXPERT_SLOTS } from '../../types/slotRequest';
-import { AnimatedPage } from '../Animate';
-import { useSnackbar } from '../../contexts/SnackbarContext';
-import UnauthorizedNotice from '../../layouts/UnauthorizedNotice';
-import { findGroupById, listenGroupsByExpertRole } from '../../utils/firebase/firestore/groups';
-import { listenExpertRequestsByExpert } from '../../utils/firebase/firestore/expertRequests';
-import { findUsersByIds, onUserProfile, updateUserProfile } from '../../utils/firebase/firestore/user';
-import ExpertRequestCard from '../ExpertRequests/ExpertRequestCard';
-import { SlotRequestButton } from '../ExpertRequests/SlotRequestDialog';
-
-interface ExpertRequestViewModel {
- request: ExpertRequest;
- group: ThesisGroup | null;
- requester: UserProfile | null;
- usersByUid: Map;
-}
-
-function formatMinimumCapacityMessage(currentCount: number): string {
- return `You currently expert ${currentCount} group${currentCount === 1 ? '' : 's'}. Slots cannot go below that.`;
-}
-
-export interface ExpertRequestsPageProps {
- role: ExpertRequestRole;
- roleLabel: string;
- allowedRoles?: UserRole[];
-}
-
-function useExpertRequestViewModels(requests: ExpertRequest[]): ExpertRequestViewModel[] {
- const [groupsById, setGroupsById] = React.useState