Skip to content
Open
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
26 changes: 26 additions & 0 deletions src/app/admin/dashboard/spark/teams/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { SearchParams } from "@/types/dashboard";
import Spark from "@/components/admin/dashboards/sparkteam";
import { parseSearchParams } from "@/utils/parseSearchParams";

export const metadata = {
title: "Spark Teams",
};

interface RawSearchParams {
[key: string]: string | string[] | undefined;
}

interface PageProps {
searchParams?: Promise<RawSearchParams>;
}

const Page = async ({ searchParams }: PageProps) => {
const resolvedSearchParams: RawSearchParams = searchParams
? await searchParams
: {};
const parsedSearchParams: SearchParams =
parseSearchParams(resolvedSearchParams);
return <Spark searchParams={parsedSearchParams} />;
};

export default Page;
22 changes: 16 additions & 6 deletions src/app/api/dashboard/[type]/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export const GET = async (req, context) => {
selected: false,
hidden: false,
interviewNotes: data.interviewNotes?.[firestoreType] ?? "",
team: data.team?.[firestoreType] ?? "",
});
});

Expand Down Expand Up @@ -207,14 +208,23 @@ export const PUT = async (req, context) => {
{ status: auth },
);
}

try {
if (types.has(params.type)) {
objects.map(async (object) => {
await updateDoc(doc(db, "users", object.uid), {
[`roles.${firestoreType}`]: status,
[`interviewNotes.${params.type}`]: object.interviewNotes,
});
});
await Promise.all(
objects.map(async (object) => {
const updateData = {
[`roles.${firestoreType}`]: status,
};
if (object.interviewNotes !== undefined) {
updateData[`interviewNotes.${params.type}`] = object.interviewNotes;
}
if (object.team !== undefined) {
updateData[`team.${params.type}`] = object.team;
}
await updateDoc(doc(db, "users", object.uid), updateData);
}),
);
}
return res.json({ message: "OK" }, { status: 200 });
} catch (err) {
Expand Down
7 changes: 6 additions & 1 deletion src/components/admin/dashboards/dashboard/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface DashboardProps<T extends keyof DashboardTypeMap> {
columns: ColumnType<DashboardTypeMap[T]>[];
tags: Tags[];
dashboardType: T;
displayFilter?: (item: DashboardTypeMap[T]) => boolean;
}

export interface Filter {
Expand All @@ -37,6 +38,7 @@ const Dashboard = <T extends keyof DashboardTypeMap>({
searchParams,
tags,
statuses,
displayFilter,
}: DashboardProps<T>) => {
const [filters, setFilters] = useState<Filter[]>([
{ id: "status", value: Object.keys(statuses) },
Expand Down Expand Up @@ -86,7 +88,10 @@ const Dashboard = <T extends keyof DashboardTypeMap>({

if (queryData && isMounted) {
const flattenedData = queryData.pages.flatMap((page) => page.items || []);
if (isMounted) setData(flattenedData);
const filteredData = displayFilter
? flattenedData.filter(displayFilter)
: flattenedData;
if (isMounted) setData(filteredData);

const lastPage = queryData.pages[queryData.pages.length - 1];
if (isMounted) setMeta({ total: lastPage.total, last: lastPage.last });
Expand Down
83 changes: 83 additions & 0 deletions src/components/admin/dashboards/dashboard/teamSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
import { useState, useEffect } from "react";
import { getDoc, doc } from "firebase/firestore";
import { db } from "@/utils/firebase";

interface teamSelectTypes {
uid: number;
currentTeam: string;
status: string;
track: string;
}

const TeamSelect = ({ uid, status, currentTeam, track }: teamSelectTypes) => {
const [newTeam, setNewTeam] = useState(currentTeam);
const [sparkProjects, setSparkProjects] = useState([]);

const getSparkProjects = async () => {
try {
const docRef = doc(db, "projects", "spark");
const docSnap = await getDoc(docRef);

if (docSnap.exists()) {
const sparkData = docSnap.data();
setSparkProjects(sparkData.projects);
} else {
console.log("No spark projects!");
}
} catch (error) {
console.error("Error fetching spark projects:", error);
}
};

useEffect(() => {
getSparkProjects();
}, []);

const handleSaveChanges = async (teamName: string) => {
try {
const res = await fetch(`/api/dashboard/${track}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
objects: [{ uid, team: teamName }],
status: status,
}),
});
if (res.ok) {
setNewTeam(teamName);
}
} catch (err) {
console.error("Failed to update team", err);
}
};

return (
<div className="hover:cursor-pointer">
<DropdownMenu>
<DropdownMenuTrigger>
<div className="bg-starlight-table-selected mt-2 cursor-pointer rounded-lg border-none px-2 text-center">
{newTeam || "TBD"}
</div>
</DropdownMenuTrigger>
<DropdownMenuContent>
{sparkProjects.map((project, index) => (
<DropdownMenuItem
key={index}
onClick={() => handleSaveChanges(project)}
>
{project}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
);
};

export default TeamSelect;
32 changes: 32 additions & 0 deletions src/components/admin/dashboards/sparkteam.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";
import { SearchParams } from "@/types/dashboard";
import { STATUSES } from "@/data/statuses";
import Dashboard from "@/components/admin/dashboards/dashboard/dashboard";
import { TAGS, COLUMNS } from "@/data/admin/sparkteam";
import { useSession } from "next-auth/react";
import Fault from "@/utils/error";

interface SparkProps {
searchParams: SearchParams;
}

const Spark = ({ searchParams }: SparkProps) => {
const session = useSession();
if (session?.data?.user?.affiliation?.includes("Spark")) {
return (
<Dashboard
searchParams={searchParams}
title="Spark"
columns={COLUMNS}
statuses={STATUSES}
tags={TAGS}
dashboardType="member"
displayFilter={(member) => member.status === "1"}
/>
);
} else {
throw new Fault(403, "Unauthorized", "You do not have access to this page");
}
};

export default Spark;
123 changes: 123 additions & 0 deletions src/data/admin/sparkteam.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"use client";

import { Tags } from "@/types/dashboard";
import { Member } from "@/types/users";
import { generateSelect, generateStatus } from "./columns";
import { STATUSES } from "@/data/statuses";
import { ColumnType } from "@/types/dashboard";
import TeamSelect from "@/components/admin/dashboards/dashboard/teamSelect";

export const TAGS: Tags[] = [
{
text: "accept",
value: "1",
},
{
text: "reject",
value: "-1",
},
];

export const COLUMNS: ColumnType<Member>[] = [
generateSelect(),
{
accessorFn: (row) => `${row.firstName} ${row.lastName}`,
id: "name",
accessorKey: "name",
header: "Name",
enableColumnFilter: true,
filterFn: "includesString",
searchable: true,
cell: ({ row }) => (
<div
onClick={(e) => {
row.getToggleSelectedHandler()(e);
row.getToggleExpandedHandler()();
}}
className="hover:cursor-pointer"
>
{row.getValue("name")}
</div>
),
},
{
accessorKey: "email",
header: "Email",
enableColumnFilter: true,
filterFn: "includesString",
searchable: true,
cell: ({ row }) => (
<div
onClick={(e) => {
row.getToggleSelectedHandler()(e);
row.getToggleExpandedHandler()();
}}
className="hover:cursor-pointer"
>
{row.getValue("email")}
</div>
),
},
{
accessorKey: "discord",
header: "Discord",
enableColumnFilter: true,
filterFn: "includesString",
searchable: true,
cell: ({ row }) => (
<div
onClick={(e) => {
row.getToggleSelectedHandler()(e);
row.getToggleExpandedHandler()();
}}
className="hover:cursor-pointer"
>
{row.getValue("discord")}
</div>
),
},
{
accessorKey: "pastProjects",
header: "Past Projects",
enableColumnFilter: true,
filterFn: "includesString",
searchable: true,
cell: ({ row }) => (
<div
onClick={(e) => {
row.getToggleSelectedHandler()(e);
row.getToggleExpandedHandler()();
}}
className="hover:cursor-pointer"
>
{row.getValue("pastProjects")}
</div>
),
},
{
accessorKey: "team",
header: "Team",
enableColumnFilter: true,
filterFn: "includesString",
searchable: true,
cell: ({ row }) => (
<div
onClick={(e) => {
row.getToggleSelectedHandler()(e);
row.getToggleExpandedHandler()();
}}
className="hover:cursor-pointer"
>
<TeamSelect
uid={row.original.uid}
currentTeam={row.getValue("team")}
status={row.getValue("status")}
track="spark"
/>
</div>
),
},

generateStatus(STATUSES),
];
export type SparkColumnsProps = typeof COLUMNS;
12 changes: 12 additions & 0 deletions src/data/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ export const TABS: Tabs = {
},
],
},
Teams: {
expand: true,
tabs: [
{
name: "Spark",
link: "/admin/dashboard/spark/teams",
icon: <FaLock className={iconStyle} />,
target: "_self",
affiliation: ["Spark", "ACM Board"],
},
],
},
Services: {
expand: true,
tabs: [
Expand Down
6 changes: 6 additions & 0 deletions src/types/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ export type Member = {
create: string;
das: string;
};
team: {
spark: string;
forge: string;
create: string;
das: string;
};
};

export type Admin = {
Expand Down
Loading