Skip to content

Commit eaa896b

Browse files
chore: merge branch 'hackathon' into sgunter/calendar-bottom-bar
2 parents 0fe8e32 + a03bcf1 commit eaa896b

File tree

5 files changed

+90
-36
lines changed

5 files changed

+90
-36
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"clsx": "^2.1.0",
2525
"highcharts": "^11.3.0",
2626
"highcharts-react-official": "^3.2.1",
27+
"html2canvas": "^1.4.1",
2728
"react": "^18.2.0",
2829
"react-devtools-core": "^5.0.0",
2930
"react-dom": "^18.2.0",

pnpm-lock.yaml

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/views/components/ImportantLinks.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function ImportantLinks({ className }: Props) {
1717
<Text variant='h3'>Important Links</Text>
1818
<a
1919
href='https://utdirect.utexas.edu/apps/registrar/course_schedule/20242/'
20-
className='text-ut-burntorange flex items-center gap-0.5'
20+
className='flex items-center gap-0.5 text-ut-burntorange'
2121
target='_blank'
2222
rel='noreferrer'
2323
>
@@ -26,7 +26,7 @@ export default function ImportantLinks({ className }: Props) {
2626
</a>
2727
<a
2828
href='https://utdirect.utexas.edu/apps/registrar/course_schedule/20236/'
29-
className='text-ut-burntorange flex items-center gap-0.5'
29+
className='flex items-center gap-0.5 text-ut-burntorange'
3030
target='_blank'
3131
rel='noreferrer'
3232
>
@@ -35,7 +35,7 @@ export default function ImportantLinks({ className }: Props) {
3535
</a>
3636
<a
3737
href='https://utdirect.utexas.edu/registrar/ris.WBX'
38-
className='text-ut-burntorange flex items-center gap-0.5'
38+
className='flex items-center gap-0.5 text-ut-burntorange'
3939
target='_blank'
4040
rel='noreferrer'
4141
>
@@ -44,7 +44,7 @@ export default function ImportantLinks({ className }: Props) {
4444
</a>
4545
<a
4646
href='https://utdirect.utexas.edu/registration/chooseSemester.WBX'
47-
className='text-ut-burntorange flex items-center gap-0.5'
47+
className='flex items-center gap-0.5 text-ut-burntorange'
4848
target='_blank'
4949
rel='noreferrer'
5050
>
@@ -53,7 +53,7 @@ export default function ImportantLinks({ className }: Props) {
5353
</a>
5454
<a
5555
href='https://utdirect.utexas.edu/apps/degree/audits/'
56-
className='text-ut-burntorange flex items-center gap-0.5'
56+
className='flex items-center gap-0.5 text-ut-burntorange'
5757
target='_blank'
5858
rel='noreferrer'
5959
>

src/views/components/common/CalendarGrid/CalendarGrid.tsx

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React from 'react';
1+
import React, { useRef } from 'react';
2+
import html2canvas from 'html2canvas';
23
import { DAY_MAP } from 'src/shared/types/CourseMeeting';
34
import { CalendarGridCourse } from 'src/views/hooks/useFlattenedCourseSchedule';
45
import calIcon from 'src/assets/icons/cal.svg';
@@ -34,11 +35,25 @@ interface Props {
3435
* @param props
3536
*/
3637
function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Props>): JSX.Element {
38+
const calendarRef = useRef(null); // Create a ref for the calendar grid
39+
40+
const saveAsPNG = () => {
41+
if (calendarRef.current) {
42+
html2canvas(calendarRef.current).then(canvas => {
43+
// Create an a element to trigger download
44+
const a = document.createElement('a');
45+
a.href = canvas.toDataURL('image/png');
46+
a.download = 'calendar.png';
47+
a.click();
48+
});
49+
}
50+
};
51+
3752
return (
3853
<div className={styles.calendar}>
3954
<div className={styles.dayLabelContainer} />
4055
{/* Displaying the rest of the calendar */}
41-
<div className={styles.timeAndGrid}>
56+
<div ref={calendarRef} className={styles.timeAndGrid}>
4257
{/* <div className={styles.timeColumn}>
4358
<div className={styles.timeBlock}></div>
4459
{hoursOfDay.map((hour) => (
@@ -57,7 +72,9 @@ function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Pr
5772
{day}
5873
</div>
5974
))}
60-
{grid.map(row => row)}
75+
{grid.map((row, index) => (
76+
<React.Fragment key={index}>{row}</React.Fragment>
77+
))}
6178
</div>
6279
</div>
6380
{courseCells.map((block: CalendarGridCourse) => (
@@ -82,7 +99,7 @@ function CalendarGrid({ courseCells, saturdayClass }: React.PropsWithChildren<Pr
8299
Save as .CAL
83100
</button>
84101
<div className={styles.divider} /> {/* Second divider */}
85-
<button className={styles.calendarButton}>
102+
<button onClick={saveAsPNG} className={styles.calendarButton}>
86103
<img src={pngIcon} className={styles.buttonIcon} alt='PNG' />
87104
Save as .PNG
88105
</button>
+29-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CalendarCourseCellProps } from 'src/views/components/common/CalendarCourseCell/CalendarCourseCell';
22
import useSchedules from './useSchedules';
33

4-
const dayToNumber = {
4+
const dayToNumber: { [day: string]: number } = {
55
Monday: 0,
66
Tuesday: 1,
77
Wednesday: 2,
@@ -15,18 +15,25 @@ interface CalendarGridPoint {
1515
endIndex: number;
1616
}
1717

18+
/**
19+
* Return type of useFlattenedCourseSchedule
20+
*/
1821
export interface CalendarGridCourse {
1922
calendarGridPoint?: CalendarGridPoint;
2023
componentProps: CalendarCourseCellProps;
2124
}
2225

2326
const convertMinutesToIndex = (minutes: number): number => Math.floor(minutes - 420 / 30);
2427

25-
export function useFlattenedCourseSchedule() {
28+
/**
29+
* Get the active schedule, and convert it to be render-able into a calendar.
30+
* @returns CalendarGridCourse
31+
*/
32+
export function useFlattenedCourseSchedule(): CalendarGridCourse[] {
2633
const [activeSchedule] = useSchedules();
2734
const { courses } = activeSchedule;
2835

29-
const out = courses.flatMap(course => {
36+
return courses.flatMap(course => {
3037
const {
3138
status,
3239
department,
@@ -43,43 +50,38 @@ export function useFlattenedCourseSchedule() {
4350
courseDeptAndInstr,
4451
status,
4552
colors: {
53+
// TODO: figure out colors - these are defaults
4654
primaryColor: 'ut-gray',
4755
secondaryColor: 'ut-gray',
4856
},
4957
},
5058
},
5159
];
5260
}
61+
62+
// in-person
5363
return meetings.flatMap(meeting => {
5464
const { days, startTime, endTime, location } = meeting;
5565
const time = meeting.getTimeString({ separator: ' - ', capitalize: true });
5666
const timeAndLocation = `${time} - ${location ? location.building : 'WB'}`;
5767

58-
return days.map(d => {
59-
const dayIndex = dayToNumber[d];
60-
const startIndex = convertMinutesToIndex(startTime);
61-
const endIndex = convertMinutesToIndex(endTime);
62-
const calendarGridPoint: CalendarGridPoint = {
63-
dayIndex,
64-
startIndex,
65-
endIndex,
66-
};
67-
68-
return {
69-
calendarGridPoint,
70-
componentProps: {
71-
courseDeptAndInstr,
72-
timeAndLocation,
73-
status,
74-
colors: {
75-
primaryColor: 'ut-orange',
76-
secondaryColor: 'ut-orange',
77-
},
68+
return days.map(d => ({
69+
calendarGridPoint: {
70+
dayIndex: dayToNumber[d],
71+
startIndex: convertMinutesToIndex(startTime),
72+
endIndex: convertMinutesToIndex(endTime),
73+
},
74+
componentProps: {
75+
courseDeptAndInstr,
76+
timeAndLocation,
77+
status,
78+
colors: {
79+
// TODO: figure out colors - these are defaults
80+
primaryColor: 'ut-orange',
81+
secondaryColor: 'ut-orange',
7882
},
79-
};
80-
});
83+
},
84+
}));
8185
});
8286
});
83-
84-
return out;
8587
}

0 commit comments

Comments
 (0)