Skip to content

Commit

Permalink
feat: complete s/u filter
Browse files Browse the repository at this point in the history
  • Loading branch information
leomotors committed Aug 11, 2023
1 parent 886b485 commit 5064bd1
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 17 deletions.
12 changes: 12 additions & 0 deletions apps/api/src/course/course.enum.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,15 @@ enum GenEdType {
"""
NO
}

enum GradingType {
"""
S/U
"""
S_U

"""
Letter Grade
"""
LETTER
}
5 changes: 5 additions & 0 deletions apps/api/src/course/course.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ input FilterInput {
"""
genEdTypes: [GenEdType!]

"""
List of `GradingTypes`. This filter is passed IF the course's has S/U in Credit Hours. If both filter are given, filters have no effect.
"""
gradingTypes: [GradingType!]

"""
List of `DayOfWeeks`. This filter is passed IF ANY of the course's sections have class in ANY of the `dayOfWeeks` in the list.
"""
Expand Down
9 changes: 9 additions & 0 deletions apps/api/src/course/course.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class CourseService {
{
keyword = '',
genEdTypes = [],
gradingTypes,
dayOfWeeks = [],
limit = 10,
offset = 0,
Expand All @@ -83,6 +84,14 @@ export class CourseService {
query.genEdType = { $in: genEdTypes }
}

if (gradingTypes && !(gradingTypes.includes('LETTER') && gradingTypes.includes('SU'))) {
if (gradingTypes.includes('LETTER')) {
query.creditHours = { $not: /S\/U/ }
} else if (gradingTypes.includes('SU')) {
query.creditHours = /S\/U/
}
}

if (dayOfWeeks.length > 0) {
query['sections.classes.dayOfWeek'] = { $in: dayOfWeeks }
}
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
export type DayOfWeek = "MO" | "TU" | "WE" | "TH" | "FR" | "SA" | "SU" | "IA" | "AR";
export type StudyProgram = "S" | "T" | "I";
export type GenEdType = "SO" | "HU" | "SC" | "IN" | "NO";
export type GradingType = "S_U" | "LETTER";
export type ReviewInteractionType = "L" | "D";
export type ReviewStatus = "APPROVED" | "REJECTED" | "PENDING";

Expand Down Expand Up @@ -37,6 +38,7 @@ export class PeriodRangeInput {
export class FilterInput {
keyword?: Nullable<string>;
genEdTypes?: Nullable<GenEdType[]>;
gradingTypes?: Nullable<GradingType[]>;
dayOfWeeks?: Nullable<DayOfWeek[]>;
periodRange?: Nullable<PeriodRangeInput>;
limit?: Nullable<number>;
Expand Down
12 changes: 10 additions & 2 deletions apps/web/src/common/components/Chips/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ChipOutlinedHighlightColor,
} from '@web/configs/theme/overrides/chip'

import { DayOfWeek, GenEdType } from '@cgr/codegen'
import { DayOfWeek, GenEdType, GradingType } from '@cgr/codegen'

/*
* This configuration file provide the Chip's types.
Expand Down Expand Up @@ -33,6 +33,13 @@ export const genEdChipConfig: GenEdChipConfigProps = {
NO: { label: 'ไม่ใช่ Gened', color: 'deepGrayOutlined', variant: 'outlined' },
}

export type GradingChipKey = GradingType
export type GradingChipConfigProps = Record<GradingChipKey, ChipConfigProps>
export const gradingChipConfig: GradingChipConfigProps = {
S_U: { label: 'S/U Grade', color: 'blueOutlined', variant: 'outlined' },
LETTER: { label: 'Letter Grade', color: 'orangeOutlined', variant: 'outlined' },
}

export type DayChipKey = DayOfWeek
export type DayChipConfigProps = Record<DayChipKey, ChipConfigProps>
export const dayChipConfig: DayChipConfigProps = {
Expand Down Expand Up @@ -67,9 +74,10 @@ export const otherChipConfig: OtherChipConfigProps = {
// Add more Chips here; don't forget to add key into `OtherChipKey` too
}

export type GeneralChipKey = GenEdChipKey | DayChipKey | OtherChipKey
export type GeneralChipKey = GenEdChipKey | GradingChipKey | DayChipKey | OtherChipKey
export const chipConfig = {
...genEdChipConfig,
...gradingChipConfig,
...dayChipConfig,
...otherChipConfig,
}
1 change: 1 addition & 0 deletions apps/web/src/common/context/Analytics/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const SNACKBAR_BUTTON = 'snackbar_button'
export const SELECTED_COURSES_BUTTON = 'selected_courses_button'
export const DAY_FILTER = 'day_search_filter'
export const GENED_FILTER = 'gened_search_filter'
export const GRADING_FILTER = 'grading_search_filter'
export const PERIOD_RANGE_FILTER = 'period_range_filter'
export const SHOPPING_CART_BUTTON = 'shopping_cart_button'
export const SHOPPING_CART_REMOVE_COURSE = 'shopping_cart_remove_course'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ export const CheckboxGroup: React.FC<CheckboxGroupProps> = ({ title, checkboxes,

const hasChecked = (tag: GeneralChipKey) => {
const genEdTags: string[] = searchCourseQueryParams.filter?.genEdTypes ?? []
const gradingTypes: string[] = searchCourseQueryParams.filter?.gradingTypes ?? []
const dayOfWeeks: string[] = searchCourseQueryParams.filter?.dayOfWeeks ?? []

return genEdTags.includes(tag) || dayOfWeeks.includes(tag)
return genEdTags.includes(tag) || gradingTypes.includes(tag) || dayOfWeeks.includes(tag)
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DayChipKey, GenEdChipKey } from '@web/common/components/Chips/config'
import { DayChipKey, GenEdChipKey, GradingChipKey } from '@web/common/components/Chips/config'
import { CreateCheckbox } from '@web/modules/CourseSearch/components/FilterSection/hooks/useFilterBar'

import { DayOfWeek, GenEdType } from '@cgr/codegen'
import { DayOfWeek, GenEdType, GradingType } from '@cgr/codegen'

export const createGenEdCheckboxes: CreateCheckbox<GenEdChipKey>[] = [
{
Expand All @@ -26,6 +26,17 @@ export const createGenEdCheckboxes: CreateCheckbox<GenEdChipKey>[] = [
},
]

export const createGradingCheckboxes: CreateCheckbox<GradingChipKey>[] = [
{
label: 'S/U Grade',
value: GradingType.SU,
},
{
label: 'Letter Grade',
value: GradingType.Letter,
},
]

export const createDayOfWeekCheckboxes: CreateCheckbox<DayChipKey>[] = [
{
label: 'วันจันทร์',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useCallback, useMemo } from 'react'

import { DayChipKey, GenEdChipKey, GeneralChipKey } from '@web/common/components/Chips/config'
import {
DayChipKey,
GenEdChipKey,
GeneralChipKey,
GradingChipKey,
} from '@web/common/components/Chips/config'
import { useSearchCourseQueryParams } from '@web/modules/CourseSearch/hooks/useSearchCourseQueryParams'

import { SearchCourseQueryVariables } from '@cgr/codegen'
Expand All @@ -16,7 +21,10 @@ export interface CreateCheckbox<Value> {

export function useFilterBar<TagValue extends GeneralChipKey = GeneralChipKey>(
initCheckboxes: CreateCheckbox<TagValue>[],
type?: keyof Pick<SearchCourseQueryVariables['filter'], 'genEdTypes' | 'dayOfWeeks'>
type?: keyof Pick<
SearchCourseQueryVariables['filter'],
'genEdTypes' | 'gradingTypes' | 'dayOfWeeks'
>
) {
const { setFilter, searchCourseQueryParams } = useSearchCourseQueryParams()

Expand All @@ -30,7 +38,16 @@ export function useFilterBar<TagValue extends GeneralChipKey = GeneralChipKey>(
: (removeTag(searchCourseQueryParams.filter.genEdTypes, tag) as GenEdChipKey[])

setFilter({ ...searchCourseQueryParams.filter, genEdTypes: genEdTypes })
} else if (type == 'dayOfWeeks') {
} else if (type === 'gradingTypes') {
const gradingTypes: GradingChipKey[] = checked
? ([tag] as GradingChipKey[])
: (removeTag(searchCourseQueryParams.filter.gradingTypes, tag) as GradingChipKey[])

setFilter({
...searchCourseQueryParams.filter,
gradingTypes,
})
} else if (type === 'dayOfWeeks') {
const dayOfWeeks: DayChipKey[] = checked
? (addTag(searchCourseQueryParams.filter.dayOfWeeks, tag) as DayChipKey[])
: (removeTag(searchCourseQueryParams.filter.dayOfWeeks, tag) as DayChipKey[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import { DialogContent, Stack, useTheme } from '@mui/material'
import useMediaQuery from '@mui/material/useMediaQuery'
import useGoogleOptimize from '@react-hook/google-optimize'

import { DayChipKey, GenEdChipKey } from '@web/common/components/Chips/config'
import { DayChipKey, GenEdChipKey, GradingChipKey } from '@web/common/components/Chips/config'
import { ResponsiveDialog } from '@web/common/components/ResponsiveDialog'
import { Analytics } from '@web/common/context/Analytics/components/Analytics'
import {
DAY_FILTER,
GENED_FILTER,
GRADING_FILTER,
PERIOD_RANGE_FILTER,
} from '@web/common/context/Analytics/constants'
import { GOOGLE_OPTIMIZA_FILTER_ORDER } from '@web/env'
import { CheckboxGroup } from '@web/modules/CourseSearch/components/CheckboxGroup'
import {
createDayOfWeekCheckboxes, // createSpecialCheckboxes,
createGenEdCheckboxes,
createGradingCheckboxes,
} from '@web/modules/CourseSearch/components/FilterSection/constants'
import { FilterSectionProps } from '@web/modules/CourseSearch/components/FilterSection/types'
import { tail } from '@web/utils/tail'
Expand All @@ -29,10 +31,15 @@ export const FilterSection: React.FC<FilterSectionProps> = ({ open, handleClose
createGenEdCheckboxes,
'genEdTypes'
)
const { checkboxes: gradingCheckboxes } = useFilterBar<GradingChipKey>(
createGradingCheckboxes,
'gradingTypes'
)
const { checkboxes: dayOfWeekCheckboxes } = useFilterBar<DayChipKey>(
createDayOfWeekCheckboxes,
'dayOfWeeks'
)

// const { checkboxes: specialCheckboxes } = useFilterBar(createSpecialCheckboxes)

const hasTags = useHasTags()
Expand All @@ -42,7 +49,7 @@ export const FilterSection: React.FC<FilterSectionProps> = ({ open, handleClose
const isExperimentOrder = useGoogleOptimize(GOOGLE_OPTIMIZA_FILTER_ORDER, [false, true])

const filters = [
<Analytics key={1} elementName={GENED_FILTER}>
<Analytics key={0} elementName={GENED_FILTER}>
{({ log }) => (
<CheckboxGroup
log={log}
Expand All @@ -52,6 +59,16 @@ export const FilterSection: React.FC<FilterSectionProps> = ({ open, handleClose
/>
)}
</Analytics>,
<Analytics key={1} elementName={GRADING_FILTER}>
{({ log }) => (
<CheckboxGroup
log={log}
id="gradingFilter"
title="วิธีการวัดผล"
checkboxes={gradingCheckboxes}
/>
)}
</Analytics>,
<Analytics key={2} elementName={DAY_FILTER}>
{({ log }) => (
<CheckboxGroup
Expand Down
24 changes: 19 additions & 5 deletions apps/web/src/modules/CourseSearch/components/TagList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import React from 'react'
import { useTranslation } from 'react-i18next'

import { GeneralChip } from '@web/common/components/Chips'
import { DayChipKey, GenEdChipKey, OtherEnum } from '@web/common/components/Chips/config'
import {
DayChipKey,
GenEdChipKey,
GradingChipKey,
OtherEnum,
} from '@web/common/components/Chips/config'
import { StyledStack } from '@web/modules/CourseSearch/components/TagList/styled'
import { useSearchCourseQueryParams } from '@web/modules/CourseSearch/hooks/useSearchCourseQueryParams'

export const TagList: React.FC = () => {
const { searchCourseQueryParams, setFilter } = useSearchCourseQueryParams()
const { filter } = searchCourseQueryParams
const { genEdTypes, dayOfWeeks, periodRange } = filter
const { genEdTypes, gradingTypes, dayOfWeeks, periodRange } = filter
const { t } = useTranslation('tagList')

const handleDeleteGenEdTag = (tag: GenEdChipKey) => {
Expand All @@ -18,6 +23,12 @@ export const TagList: React.FC = () => {
setFilter({ ...searchCourseQueryParams.filter, genEdTypes: modifiedGenEdTags })
}

const handleDeleteGradingTag = (tag: GradingChipKey) => {
if (!gradingTypes) return
const modifiedGradingTags = gradingTypes.filter((currentTag) => currentTag !== tag)
setFilter({ ...searchCourseQueryParams.filter, gradingTypes: modifiedGradingTags })
}

const handleDeleteDayOfWeekTag = (tag: DayChipKey) => {
if (!dayOfWeeks) return
const modifiedDayOfWeekTags = dayOfWeeks.filter((currentTag) => currentTag !== tag)
Expand All @@ -28,7 +39,7 @@ export const TagList: React.FC = () => {
setFilter({ ...searchCourseQueryParams.filter, periodRange: undefined })
}

if (!genEdTypes?.length && !dayOfWeeks?.length && !periodRange) {
if (!genEdTypes?.length && !gradingTypes?.length && !dayOfWeeks?.length && !periodRange) {
return null
}

Expand All @@ -37,6 +48,9 @@ export const TagList: React.FC = () => {
{genEdTypes?.map((tag) => (
<GeneralChip key={tag} type={tag} onDelete={() => handleDeleteGenEdTag(tag)} />
))}
{gradingTypes?.map((tag) => (
<GeneralChip key={tag} type={tag} onDelete={() => handleDeleteGradingTag(tag)} />
))}
{dayOfWeeks?.map((tag) => (
<GeneralChip key={tag} type={tag} onDelete={() => handleDeleteDayOfWeekTag(tag)} />
))}
Expand All @@ -55,6 +69,6 @@ export const TagList: React.FC = () => {
export function useHasTags() {
const { searchCourseQueryParams } = useSearchCourseQueryParams()
const { filter } = searchCourseQueryParams
const { genEdTypes, dayOfWeeks } = filter
return !!(genEdTypes?.length || dayOfWeeks?.length)
const { genEdTypes, gradingTypes, dayOfWeeks } = filter
return !!(genEdTypes?.length || gradingTypes?.length || dayOfWeeks?.length)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const useSearchCourseQueryParams = () => {
endTime: filterVars?.periodRange?.end,
keyword: filterVars.keyword,
genEdTypes: filterVars.genEdTypes?.join(','),
gradingTypes: filterVars.gradingTypes?.join(','),
dayOfWeeks: filterVars.dayOfWeeks?.join(','),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { StudyProgram } from '@cgr/codegen'
export interface QueryParams {
keyword?: string | null
genEdTypes?: string
gradingTypes?: string
dayOfWeeks?: string
limit?: number
offset?: number
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CourseGroup } from '@web/common/hooks/useCourseGroup/types'

import { DayOfWeek, GenEdType, SearchCourseQueryVariables } from '@cgr/codegen'
import { DayOfWeek, GenEdType, GradingType, SearchCourseQueryVariables } from '@cgr/codegen'

import { QueryParams } from '../../types'
import { removeUndefinedValue } from '../removeUndefinedValue'
Expand All @@ -9,14 +9,16 @@ export function extractSearchVarsFromQuery(
query: QueryParams,
courseGroup: CourseGroup
): SearchCourseQueryVariables {
const { keyword, genEdTypes, dayOfWeeks, startTime, endTime } = query
const { keyword, genEdTypes, gradingTypes, dayOfWeeks, startTime, endTime } = query

const genEdTypeArray = genEdTypes ? genEdTypes.split(',') : undefined
const gradingTypeArray = gradingTypes ? gradingTypes.split(',') : undefined
const dayOfWeekArray = dayOfWeeks ? dayOfWeeks.split(',') : undefined

const filter = removeUndefinedValue({
keyword: keyword ? keyword : undefined,
genEdTypes: genEdTypeArray ? (genEdTypeArray as GenEdType[]) : undefined,
gradingTypes: gradingTypeArray ? (gradingTypeArray as GradingType[]) : undefined,
dayOfWeeks: dayOfWeekArray ? (dayOfWeekArray as DayOfWeek[]) : undefined,
periodRange:
startTime && endTime
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/services/apollo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const cache = new InMemoryCache({
const filter = a.filter
hash += ':' + (filter.dayOfWeeks ? JSON.stringify(filter.dayOfWeeks) : '')
hash += ':' + (filter.genEdTypes ? JSON.stringify(filter.genEdTypes) : '')
hash += ':' + (filter.gradingTypes ? JSON.stringify(filter.gradingTypes) : '')
hash += ':' + (filter.periodRange ? JSON.stringify(filter.periodRange) : '')
hash += ':' + (filter.keyword || '')
return hash
Expand Down
9 changes: 9 additions & 0 deletions packages/codegen/src/generated/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ export type FilterInput = {
dayOfWeeks?: InputMaybe<Array<DayOfWeek>>;
/** List of `GenEdTypes`. This filter is passed IF the course's `genEdType` matches ANY of the `genEdTypes` in the list. */
genEdTypes?: InputMaybe<Array<GenEdType>>;
/** List of `GradingTypes`. This filter is passed IF the course's has S/U in Credit Hours. If both filter are given, filters have no effect. */
gradingTypes?: InputMaybe<Array<GradingType>>;
/**
* Keyword to search for courses. This filter is passed IF any of `courseNo`, `abbrName`,
* `courseNameTh`, or `courseNameEn` contains the keyword as a substring (except for `courseNo`
Expand Down Expand Up @@ -213,6 +215,13 @@ export enum GenEdType {
So = 'SO'
}

export enum GradingType {
/** Letter Grade */
Letter = 'LETTER',
/** S/U */
SU = 'S_U'
}

export type Mutation = {
__typename?: 'Mutation';
/**
Expand Down

0 comments on commit 5064bd1

Please sign in to comment.