Skip to content

Commit

Permalink
fix issue for react-select options
Browse files Browse the repository at this point in the history
  • Loading branch information
KobeZ123 committed Mar 27, 2024
1 parent 9d29162 commit 81ac50f
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 38 deletions.
6 changes: 6 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,9 @@ export interface MetaInfo {
build_timestamp: Maybe<number>;
environment: Maybe<string>;
}

// option object type for react-select
export type OptionObject = {
label: string | number;
value: string;
};
21 changes: 21 additions & 0 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { OptionObject } from "./types";

/** Does the given password satisfy our minimum criteria for strength? */
export const isStrongPassword = (password: string): boolean => {
const containsLettersAndNumbersRegex = /^(?=.*[a-zA-Z])(?=.*[0-9])/;
Expand All @@ -19,3 +21,22 @@ export const majorNameComparator = (a: string, b: string) => {
.toLowerCase();
return trimmedB.localeCompare(trimmedA);
};

/**
* Comparator function for sorting option objects by value Criteria: ignores
* spacing and special characters when sorting
*/
export const majorOptionObjectComparator = (
a: OptionObject,
b: OptionObject
) => {
const trimmedA = a.value
.replace(/[^A-Z0-9]/gi, "")
.trim()
.toLowerCase();
const trimmedB = b.value
.replace(/[^A-Z0-9]/gi, "")
.trim()
.toLowerCase();
return trimmedB.localeCompare(trimmedA);
};
20 changes: 14 additions & 6 deletions packages/frontend/components/Form/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
FormErrorMessage,
FormHelperText,
} from "@chakra-ui/react";
import { OptionObject } from "@graduate/common";
import Fuse from "fuse.js";
import { Control, FieldError, useController } from "react-hook-form";
import Select from "react-select";
Expand All @@ -14,6 +15,11 @@ type PlanSelectProps = {
label: string;
helperText?: string;
options: (string | number)[];
/**
* Optional list of (label, value) if the select option label and value should
* be different
*/
optionObjects?: OptionObject[];
/** Any side effects as a result of this field changing. */
onChangeSideEffect?: (val: string | null) => void;
/** The name of the react hook form field. */
Expand All @@ -35,6 +41,7 @@ type PlanSelectProps = {
export const PlanSelect: React.FC<PlanSelectProps> = ({
label,
options,
optionObjects,
helperText,
onChangeSideEffect,
name,
Expand All @@ -57,8 +64,7 @@ export const PlanSelect: React.FC<PlanSelectProps> = ({
includeScore: true,
threshold: 0.4,
}).search(inputValue);

return list.map((element) => element.item).includes(option.label);
return list.map((element) => element.item).includes(option.value);
} else {
return true;
}
Expand All @@ -70,10 +76,12 @@ export const PlanSelect: React.FC<PlanSelectProps> = ({
fieldState: { error },
} = useController({ name, control, rules });

const selectOptions: any[] = options.map((val) => ({
value: val,
label: val,
}));
const selectOptions: OptionObject[] = optionObjects
? optionObjects
: options.map((val) => ({
value: val.toString(),
label: val,
}));

const onChange = (option: any) => {
let val = option ? option.value : null;
Expand Down
5 changes: 5 additions & 0 deletions packages/frontend/components/Plan/AddPlanModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
cleanDndIdsFromStudent,
createEmptySchedule,
extractSupportedMajorNames,
extractSupportedMajorOptions,
extractSupportedMajorYears,
handleApiClientError,
noLeadOrTrailWhitespacePattern,
Expand Down Expand Up @@ -279,6 +280,10 @@ export const AddPlanModal: React.FC<AddPlanModalProps> = ({
catalogYear,
supportedMajorsData
)}
optionObjects={extractSupportedMajorOptions(
catalogYear,
supportedMajorsData
)}
onChangeSideEffect={() => {
setValue("concentration", "");
}}
Expand Down
33 changes: 18 additions & 15 deletions packages/frontend/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ const Sidebar: React.FC<SidebarProps> = memo(
creditsToTake={major.totalCreditsRequired}
helperText={sidebarHelperText}
renderCoopBlock
renderBetaMajorBlock={major.metadata?.verified !== true}
>
{courseData && (
<>
Expand Down Expand Up @@ -343,21 +344,23 @@ const SidebarContainer: React.FC<PropsWithChildren<SidebarContainerProps>> = ({
>
<Box px="md" pb="md">
<Box pb="sm">
<Flex alignItems="center" pb="sm">
<Badge
borderColor="red"
borderWidth="1px"
variant="outline"
colorScheme="red"
fontWeight="bold"
fontSize="sm"
borderRadius="md"
mr="sm"
>
BETA MAJOR
</Badge>
<HelperToolTip label={BETA_MAJOR_TOOLTIP_MSG} />
</Flex>
{renderBetaMajorBlock && (
<Flex alignItems="center" pb="sm">
<Badge
borderColor="red"
borderWidth="1px"
variant="outline"
colorScheme="red"
fontWeight="bold"
fontSize="sm"
borderRadius="md"
mr="sm"
>
BETA MAJOR
</Badge>
<HelperToolTip label={BETA_MAJOR_TOOLTIP_MSG} />
</Flex>
)}
<Flex alignItems="center" columnGap="2xs">
<Heading
as="h1"
Expand Down
50 changes: 33 additions & 17 deletions packages/frontend/utils/plan/supportedMajors.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,58 @@
import {
GetMajorsResponse,
GetSupportedMajorsResponse,
OptionObject,
majorNameComparator,
majorOptionObjectComparator,
} from "@graduate/common";

export const extractSupportedMajorYears = (
supportedMajorsData?: GetSupportedMajorsResponse
) => {
return Object.keys(supportedMajorsData?.supportedMajors ?? {});
};

/**
* Returns a list of the supported majors names as strings for the given catalog year.
*
* @param catalogYear Catalog year to search for
* @param supportedMajorsData Supported major data to extract from
* @returns A list of the supported major names for the
* given catalog year
*/
export const extractSupportedMajorNames = (
catalogYear?: number,
supportedMajorsData?: GetSupportedMajorsResponse
): string[] => {
if (!catalogYear) {
return [];
}
return Object.keys(
supportedMajorsData?.supportedMajors[catalogYear] ?? {}
).sort(majorNameComparator);
const majorMap = supportedMajorsData?.supportedMajors[catalogYear];
return Object.keys(majorMap ?? {}).sort(majorNameComparator);
};

export const extractMajorYears = (majorsData?: GetMajorsResponse) => {
return Object.keys(majorsData?.majors ?? {});
};
export const extractMajorNames = (
/**
* Returns a list of option objects for supported majors (label, value) for the
* given catalog year.
*
* @param catalogYear Catalog year to search for
* @param supportedMajorsData Supported major data to extract from
* @returns A list of the supported major option objects for
* the given catalog year
*/
export const extractSupportedMajorOptions = (
catalogYear?: number,
majorsData?: GetMajorsResponse
): string[] => {
supportedMajorsData?: GetSupportedMajorsResponse
): OptionObject[] => {
if (!catalogYear) {
return [];
}
// extract the name to information mapping for the given year
let majorMap = majorsData?.majors[catalogYear];
const majorMap = supportedMajorsData?.supportedMajors[catalogYear];
return Object.keys(majorMap ?? {})
.map(
(majorName) =>
majorName + (majorMap?.[majorName].metadata.verified ? "" : " [BETA]")
)
.sort(majorNameComparator);
.map((majorName) => {
return {
label: majorName + (majorMap?.[majorName].verified ? "" : " [BETA]"),
value: majorName,
};
})
.sort(majorOptionObjectComparator);
};

0 comments on commit 81ac50f

Please sign in to comment.