Skip to content

Commit

Permalink
Tracking New TEC Requirements (#845)
Browse files Browse the repository at this point in the history
### Summary <!-- Required -->

This pull requests implements the new TEC requirements in IDOL's submit
TEC page. It prevents members from submitting a TEC if they already
submitted one in the current 5-week period, unless they missed the last
period or they are a lead.

### Notion/Figma Link 

[https://www.notion.so/Track-new-TEC-requirements-1950ad723ce180e8b18df88a3d7f0388](https://www.notion.so/Track-new-TEC-requirements-1950ad723ce180e8b18df88a3d7f0388)

### Test Plan 


https://github.com/user-attachments/assets/de0f8025-5b54-4c30-a24b-89dc25313d18
  • Loading branch information
jujulcrane authored Mar 3, 2025
1 parent b1c7af0 commit 2bbdf01
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { TeamEventsAPI } from '../../../API/TeamEventsAPI';
import TeamEventCreditDashboard from './TeamEventsCreditDashboard';
import styles from './TeamEventCreditsForm.module.css';
import ImagesAPI from '../../../API/ImagesAPI';
import { INITIATIVE_EVENTS } from '../../../consts';
import { INITIATIVE_EVENTS, TEC_DEADLINES } from '../../../consts';

const TeamEventCreditForm: React.FC = () => {
// When the user is logged in, `useSelf` always return non-null data.
Expand All @@ -31,6 +31,53 @@ const TeamEventCreditForm: React.FC = () => {
});
}, []);

const approvedTECDates = approvedAttendance
.map((attendance) => {
const matchingEvent = teamEventInfoList.find((event) => event.uuid === attendance.eventUuid);
return matchingEvent
? {
date: new Date(matchingEvent.date),
credits: parseFloat(matchingEvent.numCredits)
}
: null;
})
.filter((entry): entry is { date: Date; credits: number } => entry !== null);

const getTECPeriod = (submissionDate: Date) => {
const currentPeriodIndex = TEC_DEADLINES.findIndex((date) => submissionDate <= date);
if (currentPeriodIndex === -1) {
return TEC_DEADLINES.length;
}
return currentPeriodIndex;
};

const tecCounts: number[] = Array.from({ length: TEC_DEADLINES.length }, () => 0);
approvedTECDates.forEach(({ date, credits }) => {
const period = getTECPeriod(date);
if (period < tecCounts.length) tecCounts[period] += credits;
});

const calculateCredits = () => {
const currentPeriod = getTECPeriod(new Date());
const previousPeriod = currentPeriod > 0 ? currentPeriod - 1 : null;

const periodCredits = tecCounts[currentPeriod] || 0;
const previousPeriodCredits = previousPeriod !== null ? tecCounts[currentPeriod - 1] : 1;

if (currentPeriod === 0) {
return periodCredits < 1 ? 1 - periodCredits : 0;
}
if (previousPeriodCredits < 1) {
return periodCredits + previousPeriodCredits < 2
? 2 - previousPeriodCredits - periodCredits
: 0;
}

return periodCredits < 1 ? 1 - periodCredits : 0;
};

const requiredCredits = calculateCredits();

const handleAddIconClick = () => {
setImages((images) => [...images, '']);
};
Expand Down Expand Up @@ -142,12 +189,32 @@ const TeamEventCreditForm: React.FC = () => {
<h1>Submit Team Event Credits</h1>
<p>
Earn team event credits for participating in DTI events! Fill out this form every time and
attach a picture of yourself at the event to receive credit.
attach a picture of yourself at the event to receive credit. The current 5-week TEC period
ends on{' '}
{getTECPeriod(new Date()) < TEC_DEADLINES.length
? TEC_DEADLINES[getTECPeriod(new Date())].toDateString()
: 'No upcoming period'}
.
</p>
<div className={styles.inline}>
<label className={styles.bold}>
Select a Team Event: <span className={styles.red_color}>*</span>
</label>
<div className={styles.bold}>
{requiredCredits > 1 && (
<span className={styles.red_color}>
You submitted {2 - requiredCredits} TEC last period so you must submit at least{' '}
{requiredCredits} TEC for this 5-week period.
</span>
)}
</div>
<div className={styles.bold}>
{requiredCredits === 0 && (
<span className={styles.red_color}>
You have already submitted a TEC for this 5-week period.
</span>
)}
</div>
<div className={styles.center_and_flex}>
{teamEventInfoList ? (
<Dropdown
Expand Down Expand Up @@ -264,6 +331,8 @@ const TeamEventCreditForm: React.FC = () => {
rejectedAttendance={rejectedAttendance}
isAttendanceLoading={isAttendanceLoading}
setPendingAttendance={setPendingAttendance}
requiredPeriodCredits={requiredCredits}
tecCounts={tecCounts}
/>
</Form>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
REQUIRED_INITIATIVE_CREDITS,
REQUIRED_LEAD_TEC_CREDITS,
REQUIRED_MEMBER_TEC_CREDITS,
INITIATIVE_EVENTS
INITIATIVE_EVENTS,
MAX_TEC_PER_5_WEEKS,
TEC_DEADLINES
} from '../../../consts';

const TeamEventCreditDashboard = (props: {
Expand All @@ -21,14 +23,18 @@ const TeamEventCreditDashboard = (props: {
rejectedAttendance: TeamEventAttendance[];
isAttendanceLoading: boolean;
setPendingAttendance: Dispatch<SetStateAction<TeamEventAttendance[]>>;
requiredPeriodCredits: number;
tecCounts: number[];
}): JSX.Element => {
const {
allTEC,
approvedAttendance,
pendingAttendance,
rejectedAttendance,
isAttendanceLoading,
setPendingAttendance
setPendingAttendance,
requiredPeriodCredits,
tecCounts
} = props;
const [image, setImage] = useState('');
const [open, setOpen] = useState(false);
Expand Down Expand Up @@ -104,7 +110,7 @@ const TeamEventCreditDashboard = (props: {
? `, with ${REQUIRED_INITIATIVE_CREDITS} of them being initiative team event credits`
: ''
}
to fulfill this requirement.`;
to fulfill this requirement, completing at least ${MAX_TEC_PER_5_WEEKS} team event credit every 5 weeks.`;
else
headerString = `Since you are a lead, you must complete ${REQUIRED_LEAD_TEC_CREDITS} total team event
credits${
Expand Down Expand Up @@ -219,10 +225,15 @@ const TeamEventCreditDashboard = (props: {
) : (
<div>
<div className={styles.inline}>
<label className={styles.bold}>
Your Approved Credits:{' '}
<span className={styles.dark_grey_color}>{approvedCredits}</span>
</label>
<label className={styles.bold}>Approved Credits per Period:</label>
<ul>
{TEC_DEADLINES.map((deadline, index) => (
<li key={index}>
Period {index + 1} (Ends: {deadline.toDateString()}):
<span className={styles.dark_grey_color}> {tecCounts[index]}</span>
</li>
))}
</ul>
</div>

{INITIATIVE_EVENTS && (
Expand All @@ -236,11 +247,20 @@ const TeamEventCreditDashboard = (props: {

<div className={styles.inline}>
<label className={styles.bold}>
Remaining Credits Needed:{' '}
<span className={styles.dark_grey_color}>{remainingCredits}</span>
Remaining Credits Needed for Current 5-Week Period:{' '}
<span className={styles.dark_grey_color}>{requiredPeriodCredits}</span>
</label>
</div>

{LEAD_ROLES.includes(userRole) && (
<div className={styles.inline}>
<label className={styles.bold}>
Remaining Total Credits Needed:{' '}
<span className={styles.dark_grey_color}>{remainingCredits}</span>
</label>
</div>
)}

{INITIATIVE_EVENTS && (
<div className={styles.inline}>
<label className={styles.bold}>
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/consts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
export const REQUIRED_INITIATIVE_CREDITS = 1;
export const REQUIRED_MEMBER_TEC_CREDITS = 3;
export const REQUIRED_LEAD_TEC_CREDITS = 6;
export const TEC_DEADLINES = [
new Date('2025-02-23'),
new Date('2025-03-30'),
new Date('2025-05-11')
];
export const MAX_TEC_PER_5_WEEKS = 1;
export const ALL_STATUS: Status[] = ['approved', 'pending', 'rejected'];
export const INITIATIVE_EVENTS = false;
export const ENABLE_COFFEE_CHAT = true;

0 comments on commit 2bbdf01

Please sign in to comment.