Skip to content

Commit

Permalink
Portal frontend 45 (#57)
Browse files Browse the repository at this point in the history
* create class table

* simplify

* quick save

* create class form props

* create class form

* Teacher auto complete field

* fix filter

* fix filter

* simplify

* fix api call

* handle query state

* prefer cache value

* delete env vars

* feedback

* use latest js package

* update packages
  • Loading branch information
SKairinos authored Sep 3, 2024
1 parent 7bef81a commit a1490ee
Show file tree
Hide file tree
Showing 21 changed files with 904 additions and 523 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
VITE_API_BASE_URL=http://localhost:8000/api/
# Service.
VITE_SERVICE_NAME=portal
VITE_SERVICE_IS_ROOT=1

# Gmail.
VITE_GMAIL_FILTERS_PASSWORD_RESET_REQUEST="from:[email protected] subject:Password reset request"
Expand Down
4 changes: 0 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
"type": "node"
},
{
"env": {
"VITE_SERVICE_IS_ROOT": "1",
"VITE_SERVICE_NAME": "portal"
},
"name": "Vite Server",
"preLaunchTask": "run",
"request": "launch",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"✅ Do add `devDependencies` below that are `peerDependencies` in the CFL package."
],
"dependencies": {
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v2.3.0",
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v2.3.1",
"crypto-js": "^4.2.0"
},
"devDependencies": {
Expand Down
7 changes: 2 additions & 5 deletions scripts/hard-install
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#!/bin/bash
set -e

cd "${BASH_SOURCE%/*}"
cd "${BASH_SOURCE%/*}/.."

rm -f ../yarn.lock
rm -rf ../node_modules
yarn cache clean codeforlife
yarn install --production=false
wget -O - https://raw.githubusercontent.com/ocadotechnology/codeforlife-workspace/main/scripts/frontend/hard-install | bash
6 changes: 2 additions & 4 deletions scripts/run
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/bin/bash
set -e

cd "${BASH_SOURCE%/*}"
cd "${BASH_SOURCE%/*}/.."

source ./setup

yarn dev
wget -O - https://raw.githubusercontent.com/ocadotechnology/codeforlife-workspace/main/scripts/frontend/run | bash
4 changes: 2 additions & 2 deletions scripts/setup
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
set -e

cd "${BASH_SOURCE%/*}"
cd "${BASH_SOURCE%/*}/.."

yarn install --production=false
wget -O - https://raw.githubusercontent.com/ocadotechnology/codeforlife-workspace/main/scripts/frontend/setup | bash
59 changes: 50 additions & 9 deletions src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,64 @@ import {
type CreateArg,
type CreateResult,
type DestroyResult,
type ListResult,
type RetrieveResult,
type UpdateArg,
type UpdateResult,
buildUrl,
tagData,
} from "codeforlife/utils/api"
import { type User, urls } from "codeforlife/api"
import {
type Class,
type SchoolTeacher,
type SchoolTeacherUser,
type User,
urls,
} from "codeforlife/api"
import getReadUserEndpoints, {
type ListUsersArg,
type ListUsersResult,
type RetrieveUserArg,
type RetrieveUserResult,
USER_TAG,
} from "codeforlife/api/endpoints/user"

import api from "."

export type {
ListUsersArg,
ListUsersResult,
RetrieveUserArg,
RetrieveUserResult,
export type RetrieveUserResult = RetrieveResult<
User,
| "first_name"
| "last_name"
| "email"
| "is_active"
| "date_joined"
| "student"
| "teacher"
> & {
requesting_to_join_class?: Class & {
teacher: SchoolTeacher & {
user: Omit<SchoolTeacherUser, "teacher" | "student">
}
}
}
export { RetrieveUserArg }

export type ListUsersResult = ListResult<
User,
| "first_name"
| "last_name"
| "email"
| "is_active"
| "date_joined"
| "student"
| "teacher",
{
requesting_to_join_class?: Class & {
teacher: SchoolTeacher & {
user: Omit<SchoolTeacherUser, "teacher" | "student">
}
}
}
>
export { ListUsersArg }

export type HandleJoinClassRequestResult = UpdateResult<User>
export type HandleJoinClassRequestArg = UpdateArg<User, never, "first_name"> & {
Expand Down Expand Up @@ -68,7 +104,12 @@ export type ValidatePasswordArg = Pick<User, "id" | "password">

const userApi = api.injectEndpoints({
endpoints: build => ({
...getReadUserEndpoints(build),
...getReadUserEndpoints<
RetrieveUserResult,
RetrieveUserArg,
ListUsersResult,
ListUsersArg
>(build),
handleJoinClassRequest: build.mutation<
HandleJoinClassRequestResult,
HandleJoinClassRequestArg
Expand Down
37 changes: 37 additions & 0 deletions src/components/form/ClassNameField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { TextField, type TextFieldProps } from "codeforlife/components/form"
import { type FC } from "react"
import { InputAdornment } from "@mui/material"
import { PeopleAlt as PeopleAltIcon } from "@mui/icons-material"
import { string as YupString } from "yup"

export type ClassNameFieldProps = Omit<
TextFieldProps,
"type" | "name" | "schema"
> &
Partial<Pick<TextFieldProps, "name">>

const ClassNameField: FC<ClassNameFieldProps> = ({
name = "name",
label = "Last name",
placeholder = "Enter a class name",
InputProps = {},
...otherTextFieldProps
}) => (
<TextField
schema={YupString().max(200)}
name={name}
label={label}
placeholder={placeholder}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<PeopleAltIcon />
</InputAdornment>
),
...InputProps,
}}
{...otherTextFieldProps}
/>
)

export default ClassNameField
32 changes: 32 additions & 0 deletions src/components/form/ReadClassmatesDataField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
CheckboxField,
type CheckboxFieldProps,
} from "codeforlife/components/form"
import { type FC } from "react"

export type ReadClassmatesDataFieldProps = Omit<
CheckboxFieldProps,
"name" | "formControlLabelProps"
> &
Partial<Pick<CheckboxFieldProps, "name" | "formControlLabelProps">>

const ReadClassmatesDataField: FC<ReadClassmatesDataFieldProps> = ({
name = "read_classmates_data",
formControlLabelProps,
...otherCheckboxFieldProps
}) => {
const {
label = "Allow students to see their classmates' progress?",
...otherFormControlLabelProps
} = formControlLabelProps || {}

return (
<CheckboxField
name={name}
formControlLabelProps={{ label, ...otherFormControlLabelProps }}
{...otherCheckboxFieldProps}
/>
)
}

export default ReadClassmatesDataField
27 changes: 27 additions & 0 deletions src/components/form/TeacherAutocompleteField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ApiAutocompleteField } from "codeforlife/components/form"
import { type FC } from "react"

import { type ListUsersArg, useLazyListUsersQuery } from "../../api/user"

export interface TeacherAutocompleteFieldProps {
required?: boolean
name?: string
_id?: ListUsersArg["_id"]
}

const TeacherAutocompleteField: FC<TeacherAutocompleteFieldProps> = ({
required = false,
name = "teacher",
_id,
}) => (
<ApiAutocompleteField
useLazyListQuery={useLazyListUsersQuery}
searchKey="name"
filterOptions={{ type: "teacher", _id }}
getOptionLabel={({ first_name, last_name }) => `${first_name} ${last_name}`}
getOptionKey={({ teacher }) => teacher!.id}
textFieldProps={{ required, name }}
/>
)

export default TeacherAutocompleteField
26 changes: 12 additions & 14 deletions src/components/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import LastNameField, { type LastNameFieldProps } from "./LastNameField"
import NewPasswordField, {
type NewPasswordFieldProps,
} from "./NewPasswordField"
import SchoolNameField, { type SchoolNameFieldProps } from "./SchoolNameField"

export {
LastNameField,
NewPasswordField,
type LastNameFieldProps,
type NewPasswordFieldProps,
SchoolNameField,
type SchoolNameFieldProps,
}
export * from "./ClassNameField"
export { default as ClassNameField } from "./ClassNameField"
export * from "./LastNameField"
export { default as LastNameField } from "./LastNameField"
export * from "./NewPasswordField"
export { default as NewPasswordField } from "./NewPasswordField"
export * from "./ReadClassmatesDataField"
export { default as ReadClassmatesDataField } from "./ReadClassmatesDataField"
export * from "./SchoolNameField"
export { default as SchoolNameField } from "./SchoolNameField"
export * from "./TeacherAutocompleteField"
export { default as TeacherAutocompleteField } from "./TeacherAutocompleteField"
Loading

0 comments on commit a1490ee

Please sign in to comment.