Skip to content

Commit b2d7b78

Browse files
opt out task created in admin (#102)
## Notion ticket link <!-- Please replace with your ticket's URL --> [Ticket Name](https://www.notion.so/uwblueprintexecs/create-task-when-user-opts-out-to-inform-admins-2fa10f3fb1dc806b8743faaf5188a7d9) <!-- Give a quick summary of the implementation details, provide design justifications if necessary --> ## Implementation description * When user opts out create task <!-- What should the reviewer do to verify your changes? Describe expected results and include screenshots when appropriate --> ## Steps to test 1. Opt out check admin page <!-- Draw attention to the substantial parts of your PR or anything you'd like a second opinion on --> ## What should reviewers focus on? * ## Checklist - [ ] My PR name is descriptive and in imperative tense - [ ] My commit messages are descriptive and in imperative tense. My commits are atomic and trivial commits are squashed or fixup'd into non-trivial commits - [ ] I have run the appropriate linter(s) - [ ] I have requested a review from the PL, as well as other devs who have background knowledge on this PR or who will be building on top of this PR
1 parent 52a3973 commit b2d7b78

File tree

8 files changed

+59
-7
lines changed

8 files changed

+59
-7
lines changed

backend/app/models/Task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TaskType(str, PyEnum):
1515
VOLUNTEER_APP_REVIEW = "volunteer_app_review"
1616
PROFILE_UPDATE = "profile_update"
1717
MATCHING = "matching"
18+
USER_OPT_OUT = "user_opt_out"
1819

1920

2021
class TaskPriority(str, PyEnum):

backend/app/schemas/task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class TaskType(str, Enum):
2020
VOLUNTEER_APP_REVIEW = "volunteer_app_review"
2121
PROFILE_UPDATE = "profile_update"
2222
MATCHING = "matching"
23+
USER_OPT_OUT = "user_opt_out"
2324

2425

2526
class TaskPriority(str, Enum):

backend/app/services/implementations/user_service.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from datetime import datetime
23
from typing import List
34
from uuid import UUID
45

@@ -18,6 +19,9 @@
1819
RankingPreference,
1920
Role,
2021
Task,
22+
TaskPriority,
23+
TaskStatus,
24+
TaskType,
2125
Treatment,
2226
User,
2327
UserData,
@@ -234,6 +238,19 @@ async def soft_delete_user_by_id(self, user_id: str):
234238
raise HTTPException(status_code=404, detail="User not found")
235239

236240
db_user.active = False
241+
242+
# Create a User Opt Out task for admin visibility (start and end date = day of opt-out)
243+
opt_out_time = datetime.utcnow()
244+
opt_out_task = Task(
245+
participant_id=db_user.id,
246+
type=TaskType.USER_OPT_OUT,
247+
priority=TaskPriority.NO_STATUS,
248+
status=TaskStatus.PENDING,
249+
start_date=opt_out_time,
250+
end_date=opt_out_time,
251+
)
252+
self.db.add(opt_out_task)
253+
237254
self.db.commit()
238255
except ValueError:
239256
raise HTTPException(status_code=400, detail="Invalid user ID format")

frontend/src/APIClients/taskAPIClient.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ export interface BackendTask {
66
participantName: string | null;
77
participantEmail: string | null;
88
participantRoleId: number | null;
9-
type: 'intake_form_review' | 'volunteer_app_review' | 'profile_update' | 'matching';
9+
type:
10+
| 'intake_form_review'
11+
| 'volunteer_app_review'
12+
| 'profile_update'
13+
| 'matching'
14+
| 'user_opt_out';
1015
priority: 'no_status' | 'low' | 'medium' | 'high';
1116
status: 'pending' | 'in_progress' | 'completed';
1217
assigneeId: string | null;
@@ -26,7 +31,12 @@ export interface TaskListResponse {
2631

2732
export interface UpdateTaskRequest {
2833
participantId?: string;
29-
type?: 'intake_form_review' | 'volunteer_app_review' | 'profile_update' | 'matching';
34+
type?:
35+
| 'intake_form_review'
36+
| 'volunteer_app_review'
37+
| 'profile_update'
38+
| 'matching'
39+
| 'user_opt_out';
3040
priority?: 'no_status' | 'low' | 'medium' | 'high';
3141
status?: 'pending' | 'in_progress' | 'completed';
3242
assigneeId?: string | null;

frontend/src/pages/admin/tasks.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const mapAPITaskToFrontend = (
8282
volunteer_app_review: 'Ranking / Secondary App Review',
8383
profile_update: 'Profile Update',
8484
matching: 'Matching',
85+
user_opt_out: 'User Opt Out',
8586
};
8687

8788
// Map backend priority to frontend priority
@@ -98,6 +99,7 @@ const mapAPITaskToFrontend = (
9899
volunteer_app_review: 'secondary_app',
99100
profile_update: 'profile_updates',
100101
matching: 'matching_requests',
102+
user_opt_out: 'user_opt_outs',
101103
};
102104

103105
// Format dates from ISO to DD/MM/YY
@@ -132,12 +134,12 @@ const mapAPITaskToFrontend = (
132134
startDate: formatDate(apiTask.startDate),
133135
endDate: apiTask.endDate ? formatDate(apiTask.endDate) : formatDate(apiTask.startDate),
134136
priority: priorityMap[apiTask.priority] || 'Add status',
135-
type: typeMap[apiTask.type] || 'Intake Form Review',
137+
type: typeMap[apiTask.type] ?? 'Intake Form Review',
136138
assignee: assignee?.name,
137139
completed: apiTask.status === 'completed',
138140
userType,
139-
category: categoryMap[apiTask.type] || 'intake_screening',
140-
description: apiTask.description || `Task for ${typeMap[apiTask.type]}`,
141+
category: categoryMap[apiTask.type] ?? 'intake_screening',
142+
description: apiTask.description ?? `Task for ${typeMap[apiTask.type] ?? 'Intake Form Review'}`,
141143
};
142144
};
143145

frontend/src/types/adminTypes.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,24 @@ export interface Task {
22
id: string;
33
name: string;
44
participantId?: string;
5-
type: 'Intake Form Review' | 'Ranking / Secondary App Review' | 'Matching' | 'Profile Update';
5+
type:
6+
| 'Intake Form Review'
7+
| 'Ranking / Secondary App Review'
8+
| 'Matching'
9+
| 'Profile Update'
10+
| 'User Opt Out';
611
startDate: string;
712
endDate: string;
813
priority: 'High' | 'Medium' | 'Low' | 'Add status';
914
assignee?: string;
1015
completed: boolean;
1116
userType: 'Participant' | 'Volunteer';
12-
category: 'intake_screening' | 'secondary_app' | 'matching_requests' | 'profile_updates';
17+
category:
18+
| 'intake_screening'
19+
| 'secondary_app'
20+
| 'matching_requests'
21+
| 'profile_updates'
22+
| 'user_opt_outs';
1323
description?: string;
1424
}
1525

@@ -32,6 +42,7 @@ export const categoryLabels: Record<Task['category'], string> = {
3242
secondary_app: 'Review secondary application / ranking forms',
3343
matching_requests: 'Participants requesting a match',
3444
profile_updates: 'User profile updates',
45+
user_opt_outs: 'User opt outs',
3546
};
3647

3748
export const taskCategories: TaskCategory[] = [
@@ -59,4 +70,10 @@ export const taskCategories: TaskCategory[] = [
5970
categoryKey: 'profile_updates',
6071
bgColor: '#EEEEEC',
6172
},
73+
{
74+
id: '5',
75+
name: 'User opt outs',
76+
categoryKey: 'user_opt_outs',
77+
bgColor: 'rgba(200, 200, 200, 0.4)',
78+
},
6279
];

frontend/src/utils/taskHelpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const getTypeColor = (type: string): { bg: string; color: string } => {
88
'Ranking / Secondary App Review': { bg: COLORS.bgTealLight, color: COLORS.teal },
99
Matching: { bg: COLORS.bgPinkLight, color: COLORS.red },
1010
'Profile Update': { bg: COLORS.bgGrayLight, color: COLORS.gray700 },
11+
'User Opt Out': { bg: 'rgba(200, 200, 200, 0.4)', color: COLORS.gray700 },
1112
};
1213
return typeColors[type] || { bg: COLORS.bgGrayLight, color: COLORS.gray700 };
1314
};
@@ -28,6 +29,7 @@ export const getCategoryColor = (categoryKey: string): string => {
2829
secondary_app: COLORS.bgTealLight,
2930
matching_requests: COLORS.bgPinkLight,
3031
profile_updates: COLORS.bgGrayLight,
32+
user_opt_outs: 'rgba(200, 200, 200, 0.4)',
3133
};
3234
return categoryColors[categoryKey] || COLORS.bgGrayLight;
3335
};

frontend/src/utils/taskLinkHelpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export const getParticipantLink = (task: Task): string => {
2020
return `${baseUrl}?tab=profile`;
2121
} else if (task.type === 'Intake Form Review' || task.type === 'Ranking / Secondary App Review') {
2222
return `${baseUrl}?tab=forms`;
23+
} else if (task.type === 'User Opt Out') {
24+
return baseUrl;
2325
} else {
2426
// Default: profile tab
2527
return baseUrl;

0 commit comments

Comments
 (0)