Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created Context for Qualifier 1 Page #502

Merged
merged 4 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion frontend/src/api_data/copData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,4 @@ function fetchAllCopData() {
return copData;
}

export { copDatum, fetchCopDataById, fetchAllCopData };
export { copData, copDatum, fetchCopDataById, fetchAllCopData };
61 changes: 61 additions & 0 deletions frontend/src/context/QualifiersContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { createContext, useContext, useState, ReactNode } from "react";

// Types
type QualifiersType = {
COPs: {
[copName: string]: string[];
};
// availabilityTimeSlots: string[];
};

type QualifiersContextType = {
qualifiers: QualifiersType;
updateQualifiers: (newQualifiers: QualifiersType) => void;
};

// Create the context
const QualifiersContext = createContext<QualifiersContextType | undefined>(
undefined
);

// Custom hook to use the qualifiers context
export const useQualifiersContext = () => {
const context = useContext(QualifiersContext);
if (!context) {
throw new Error(
"useQualifiersContext must be used within a QualifiersProvider"
);
}
return context;
};

// Provider component
export const QualifiersProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
// Initial state for qualifiers, should be fetched once the user has an account
const initialState: QualifiersType = {
COPs: {
// // Data below is for testing
// "UI/UX": [
// "UI/UX Designer",
// "UX Researcher",
// "UX Writing",
// "UX Practice Lead",
// ],
},
// availabilityTimeSlots: [],
};

const [qualifiers, setQualifiers] = useState<QualifiersType>(initialState);

const updateQualifiers = (newQualifiers: QualifiersType) => {
setQualifiers(newQualifiers);
};

return (
<QualifiersContext.Provider value={{ qualifiers, updateQualifiers }}>
{children}
</QualifiersContext.Provider>
);
};
5 changes: 3 additions & 2 deletions frontend/src/pages/QualifierPage/QualifierPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Outlet, useLoaderData } from "react-router-dom";

// Internal Imports
import { ProgressBar } from "components/components";
import { QualifiersProvider } from "context/QualifiersContext";

// Lazy Imports
const QualifierPageRoles = React.lazy(() => import("./QualifierPageRoles"));
Expand Down Expand Up @@ -47,13 +48,13 @@ function QualifierContent() {

function QualifierPage() {
return (
<Fragment>
<QualifiersProvider>
<Suspense fallback={<div>...Loading</div>}>
<main className="mx-6">
<Outlet />
</main>
</Suspense>
</Fragment>
</QualifiersProvider>
);
}

Expand Down
3 changes: 3 additions & 0 deletions frontend/src/pages/QualifierPage/QualifierPageCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import {
import { QualifierNav, QualifierTitle } from "./QualifierComponents";
import { timezones } from "../../api_data/timezoneData";
import { iconArrowLeft } from "assets/images/images";
// import { useQualifiersContext } from "context/QualifiersContext";

function QualifierPageCalendar() {
// const {qualifiers} = useQualifiersContext();
// console.log(qualifiers);
const navigate = useNavigate();

return (
Expand Down
211 changes: 141 additions & 70 deletions frontend/src/pages/QualifierPage/QualifierPageRoles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,158 @@ import { useNavigate } from "react-router-dom";
import { Button, Chip } from "components/components";
import { QualifierNav, QualifierTitle } from "./QualifierComponents";
import { fetchAllCopData, copDatum } from "api_data/copData";
import { useQualifiersContext } from "context/QualifiersContext";
import { onKey } from "components/Utility/utils";

function QualifierPageRoles() {
const [data, setData] = useState<copDatum[]>([] as copDatum[]);
const QualifierPageRoles: React.FC = () => {
// Call useContext at the top level of your component to read and subscribe to context
const { qualifiers, updateQualifiers } = useQualifiersContext();

const navigate = useNavigate();

const [data, setData] = useState<copDatum[]>([] as copDatum[]);
useEffect(() => {
setData(fetchAllCopData());
}, []);

// Initialize selectedRoles state with COP qualifiers from the context
const [selectedRoles, setSelectedRoles] = useState<{
[copName: string]: { [roleName: string]: boolean };
}>(() => {
// Convert qualifiers.COP to selectedRoles format
const selectedRolesFromQualifiers: {
[copName: string]: { [roleName: string]: boolean };
} = {};
for (const copName in qualifiers.COPs) {
selectedRolesFromQualifiers[copName] = {};
qualifiers.COPs[copName].forEach((role: string) => {
selectedRolesFromQualifiers[copName][role] = true;
});
}
return selectedRolesFromQualifiers;
});

// Toggle role selection
const handleRoleSelect = (copName: string, roleName: string) => {
setSelectedRoles((prevState) => ({
...prevState,
[copName]: {
...prevState[copName],
[roleName]: !prevState[copName]?.[roleName],
},
}));
};

// Toggle "Select all"/"Deselect all" within each COP
const handleSelectAll = (copName: string, roles: string[]) => {
setSelectedRoles((prevState) => {
const allSelected = roles.every((role) => prevState[copName]?.[role]); // Check if all roles are selected
const updatedRolesState = roles.reduce(
(acc: { [key: string]: boolean }, role) => {
acc[role] = !allSelected; // Set all roles to true if not all are currently selected, otherwise set all to false
return acc;
},
{}
);
return {
...prevState,
[copName]: updatedRolesState,
};
});
};

// Update qualifiers in the context
const handleUpdateCopQualifiers = () => {
const updatedCopQualifiers: { [copName: string]: string[] } = {};

for (const copName in selectedRoles) {
// console.log(`Cop Name: ${copName}`);
const roles = selectedRoles[copName];
// console.log("Roles:");

for (const roleName in roles) {
// console.log(`${roleName} (${typeof roleName}): ${roles[roleName]}`);
if (roles[roleName]) {
// If role is true, add it to the roles array
updatedCopQualifiers[copName] = updatedCopQualifiers[copName] || [];
updatedCopQualifiers[copName].push(roleName);
}
}
}

// console.log("Updated Cop Qualifiers:", updatedCopQualifiers);
// console.log("Old Qualifiers:", qualifiers);
const newQualifiers = { ...qualifiers, COPs: updatedCopQualifiers };

console.log("New Qualifiers:", newQualifiers);
updateQualifiers(newQualifiers); // Update qualifiers
};

return (
<Fragment>
<QualifierTitle title="What type of role are you looking for?">
Select as many roles as you'd like to find opportunities in.
</QualifierTitle>
<div className="flex-center-x">
{data.map((datum, index) => {
{data.map((cop, index) => {
return (
<Fragment key={index}>
<CopRoles copDatum={datum} />
<div className="row fill flex-center-x my-1">
<div className="col-8">
<div className="row align-center my-3 justify-between">
<div className="flex items-center">
<cop.icon
fill="black"
strokeWidth="0.2"
height="21"
aria-hidden="true"
/>
<span className="title-4 ml-1">{cop.title}</span>
</div>
<span
className="links"
tabIndex={0}
role="button"
aria-pressed={
selectedRoles[cop.title] &&
Object.values(selectedRoles[cop.title]).every(
(role) => role
)
}
onClick={() => handleSelectAll(cop.title, cop.roles)}
onKeyDown={(e) =>
onKey(
() => handleSelectAll(cop.title, cop.roles),
"Enter"
)(e)
}
>
{selectedRoles[cop.title] &&
Object.values(selectedRoles[cop.title]).every(
(role) => role
)
? "Deselect All"
: "Select All"}
</span>
</div>
<div>
{cop.roles.map((role, index) => {
return (
<Chip
key={index}
variant="multi"
addClass="mr-4 mb-4"
checked={selectedRoles[cop.title]?.[role] || false}
value={role}
onClick={() => {
handleRoleSelect(cop.title, role);
}}
/>
);
})}
</div>
</div>
</div>
{index < data.length - 1 && (
<hr className="row col-8 qroles-border"></hr>
)}
Expand All @@ -38,77 +170,16 @@ function QualifierPageRoles() {
size="lg"
length="long"
color="primary"
onClick={() => navigate("../2")}
onClick={() => {
handleUpdateCopQualifiers();
navigate("../2");
}}
>
Next
</Button>
</QualifierNav>
</Fragment>
);
}

interface CopRolesProps {
copDatum: copDatum;
}

function CopRoles({ copDatum }: CopRolesProps) {
const [isAllSelected, setIsAllSelected] = useState(false);
const [isRoleChecked, setIsRoleChecked] = useState<boolean[]>(
Array(copDatum.roles.length).fill(false)
);

function handleSelectAll() {
const copy = isRoleChecked.map((_) => !isAllSelected);
setIsRoleChecked(copy);
setIsAllSelected(!isAllSelected);
}

return (
<div className="row fill flex-center-x my-1">
<div className="col-8">
<div className="row align-center my-3 justify-between">
<div className="flex items-center">
<copDatum.icon
fill="black"
strokeWidth="0.2"
height="21"
aria-hidden="true"
/>
<span className="title-4 ml-1">{copDatum.title}</span>
</div>
<span
className="links"
tabIndex={0}
role="button"
aria-pressed={isAllSelected}
onClick={handleSelectAll}
onKeyDown={(e) => onKey(handleSelectAll, "Enter")(e)}
>
{isAllSelected ? "Deselect all" : "Select all"}
</span>
</div>
<div>
{copDatum.roles.map((role, index) => {
return (
<Chip
key={index}
variant="multi"
addClass="mr-4 mb-4"
checked={isRoleChecked[index]}
value={role}
onClick={(active, value) => {
const copy = [...isRoleChecked];
copy[index] = active;
setIsRoleChecked(copy);
console.log(isRoleChecked);
}}
/>
);
})}
</div>
</div>
</div>
);
}
};

export default QualifierPageRoles;
Loading
Loading