Skip to content
Merged
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
149 changes: 143 additions & 6 deletions src/app/(app)/settings/backoffice/exports/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,153 @@
"use client";

import { AuthCheck } from "@/components/auth-check";
import CustomCombobox from "@/components/combobox";
import SettingsWrapper from "@/components/settings-wrapper";
import { Metadata } from "next";
import {
useExportGroupEnrollments,
useExportShiftGroups,
} from "@/lib/queries/backoffice";
import { useGetAllCourses } from "@/lib/queries/courses";
import { ICourse } from "@/lib/types";
import clsx from "clsx";
import { useState } from "react";
import { twMerge } from "tailwind-merge";

function downloadFile({
data,
fileName,
fileType,
}: {
data: string;
fileName: string;
fileType: string;
}) {
const blob = new Blob([data], { type: fileType });

const a = document.createElement("a");
a.download = fileName;
a.href = window.URL.createObjectURL(blob);
const clickEvt = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true,
});
a.dispatchEvent(clickEvt);
a.remove();
}

function formatCourses(courses: ICourse[] | undefined) {
if (!courses) return [];

export const metadata: Metadata = {
title: "Pombo | Exports",
};
return courses.map((course) => {
return { id: course.id, name: course.name };
});
}

export default function Exports() {
const [selectedCourse, setSelectedCourse] = useState<{
id: string;
name: string;
} | null>(null);

const { data: allCourses } = useGetAllCourses();
const { refetch: getShiftGroups, isError: exportShiftsGroupError } =
useExportShiftGroups(selectedCourse?.id || "");
const { refetch: getGroupEnrollment, isError: exportGroupEnrollmentsError } =
useExportGroupEnrollments(selectedCourse?.id || "");

const formattedCourses = formatCourses(allCourses);

const handleShiftsGroupExport = async () => {
const result = await getShiftGroups();
downloadFile({
data: result.data,
fileName: `${selectedCourse?.name}-turmas.csv`,
fileType: "text/csv",
});
};

const handleGroupEnrollmentsExport = async () => {
const result = await getGroupEnrollment();
downloadFile({
data: result.data,
fileName: `${selectedCourse?.name}-inscrições.csv`,
fileType: "text/csv",
});
};

const validCourse = selectedCourse !== null;

return (
<AuthCheck userTypes={["admin", "professor"]}>
<SettingsWrapper title="Export data">
<div>Exports Page</div>
<title>Pombo | Exports</title>

<SettingsWrapper title="Schedule Generator">
<div className="flex h-full flex-col gap-8">
<section className="space-y-2">
<h2 className="text-2xl font-semibold">Generate new schedule</h2>
<p>Trigger the schedule generator with a few clicks</p>
</section>

<section className="space-y-6">
<div className="max-w-2xl space-y-6">
<div className="space-y-1">
<p className="pl-2 font-semibold select-none">Courses</p>
<CustomCombobox
items={formattedCourses}
selectedItem={selectedCourse}
setSelectedItem={setSelectedCourse}
/>
</div>
</div>

<div className="mt-6 inline-flex w-full max-w-2xl items-center gap-4">
<button
disabled={!validCourse}
onClick={handleShiftsGroupExport}
className={twMerge(
clsx(
"w-1/2 rounded-lg px-4 py-2 text-sm font-semibold text-white transition-all duration-200 md:text-base",
!validCourse
? "cursor-not-allowed bg-gray-400"
: "bg-primary-400 hover:bg-primary-400/95 cursor-pointer hover:scale-98",
),
)}
>
Shift Groups
</button>

<span className="text-dark/80 font-semibold">or</span>

<button
disabled={!validCourse}
onClick={handleGroupEnrollmentsExport}
className={twMerge(
clsx(
"w-1/2 rounded-lg px-4 py-2 text-sm font-semibold text-white transition-all duration-200 md:text-base",
!validCourse
? "cursor-not-allowed bg-gray-400"
: "bg-primary-400 hover:bg-primary-400/95 cursor-pointer hover:scale-98",
),
)}
>
Group Enrollments
</button>
</div>

{exportShiftsGroupError && (
<p className="text-dark/50 font-semibold">
Failed to download Shifts Group!
</p>
)}

{exportGroupEnrollmentsError && (
<p className="text-dark/50 font-semibold">
Failed to download Group Enrollment!
</p>
)}
</section>
</div>
</SettingsWrapper>
</AuthCheck>
);
Expand Down
121 changes: 62 additions & 59 deletions src/app/(app)/settings/backoffice/generator/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import { AuthCheck } from "@/components/auth-check";
import CustomSelect from "@/components/select";
import SettingsWrapper from "@/components/settings-wrapper";
import { useGenerateSchedule } from "@/lib/mutations/backoffice";
Expand Down Expand Up @@ -31,71 +32,73 @@ export default function GenerateSchedule() {
});

return (
<SettingsWrapper title="Schedule Generator">
<div className="flex h-full flex-col gap-8">
<section className="space-y-2">
<h2 className="text-2xl font-semibold">Generate new schedule</h2>
<p>Trigger the schedule generator with a few clicks</p>
</section>
<AuthCheck userTypes={["admin", "professor"]}>
<SettingsWrapper title="Schedule Generator">
<div className="flex h-full flex-col gap-8">
<section className="space-y-2">
<h2 className="text-2xl font-semibold">Generate new schedule</h2>
<p>Trigger the schedule generator with a few clicks</p>
</section>

<section className="space-y-6">
<div className="max-w-2xl space-y-6">
<div className="space-y-1">
<p className="pl-2 font-semibold">Degree</p>
<CustomSelect
items={degrees || []}
selectedItem={
selectedDegree || { id: "", name: "Select a course" }
}
setSelectedItem={setselectedDegree}
/>
</div>
<section className="space-y-6">
<div className="max-w-2xl space-y-6">
<div className="space-y-1">
<p className="pl-2 font-semibold">Degree</p>
<CustomSelect
items={degrees || []}
selectedItem={
selectedDegree || { id: "", name: "Select a course" }
}
setSelectedItem={setselectedDegree}
/>
</div>

<div className="space-y-1">
<p className="pl-2 font-semibold">Semester</p>
<CustomSelect
items={[1, 2].map((semester) => ({
id: `semester-${semester}`,
name: semester.toString(),
}))}
selectedItem={selectedSemester}
setSelectedItem={setSelectedSemester}
/>
<div className="space-y-1">
<p className="pl-2 font-semibold">Semester</p>
<CustomSelect
items={[1, 2].map((semester) => ({
id: `semester-${semester}`,
name: semester.toString(),
}))}
selectedItem={selectedSemester}
setSelectedItem={setSelectedSemester}
/>
</div>
</div>
</div>

<button
disabled={!selectedDegree}
onClick={onGenerate}
className={twMerge(
clsx(
"mt-6 min-w-1/4 rounded-lg px-4 py-2 font-semibold text-white transition-all duration-200",
!selectedDegree
? "cursor-not-allowed bg-gray-400"
: "bg-primary-400 hover:bg-primary-400/95 cursor-pointer hover:scale-98",
),
)}
>
Generate Schedule
</button>
<button
disabled={!selectedDegree}
onClick={onGenerate}
className={twMerge(
clsx(
"mt-6 min-w-1/4 rounded-lg px-4 py-2 font-semibold text-white transition-all duration-200",
!selectedDegree
? "cursor-not-allowed bg-gray-400"
: "bg-primary-400 hover:bg-primary-400/95 cursor-pointer hover:scale-98",
),
)}
>
Generate Schedule
</button>

{generateSchedule.isPending && (
<p className="text-dark/50 font-semibold">Pending...</p>
)}
{generateSchedule.isPending && (
<p className="text-dark/50 font-semibold">Pending...</p>
)}

{generateSchedule.isSuccess && (
<p className="text-dark/50 font-semibold">
{generateSchedule.data.message}
</p>
)}
{generateSchedule.isSuccess && (
<p className="text-dark/50 font-semibold">
{generateSchedule.data.message}
</p>
)}

{generateSchedule.isError && (
<p className="text-dark/50 font-semibold">
{generateSchedule.error.message}
</p>
)}
</section>
</div>
</SettingsWrapper>
{generateSchedule.isError && (
<p className="text-dark/50 font-semibold">
{generateSchedule.error.message}
</p>
)}
</section>
</div>
</SettingsWrapper>
</AuthCheck>
);
}
14 changes: 0 additions & 14 deletions src/app/(app)/settings/connections/page.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/app/(app)/settings/notifications/page.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/app/(app)/settings/preferences/page.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/app/(app)/settings/privacy/page.tsx

This file was deleted.

10 changes: 5 additions & 5 deletions src/components/calendar/event-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { EventProps } from "react-big-calendar";
import { editColor } from "@/lib/utils";

export default function EventCard({ event }: EventProps) {
const building = event.resource?.building || "";
const room = event.resource?.room || "";
const building = event.resource?.building;
const room = event.resource?.room;
const textColor = event.resource?.textColor;

const location = `${building} - ${room}`;
Expand All @@ -26,9 +26,9 @@ export default function EventCard({ event }: EventProps) {
>
<div className="space-y-0.5">
<h3>{event.title}</h3>
<p className="text-xs opacity-70 sm:text-sm">
{location || "No location"}
</p>
{building && room && (
<p className="text-xs opacity-70 sm:text-sm">{location}</p>
)}
</div>
</div>
);
Expand Down
Loading