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
1,889 changes: 1,887 additions & 2 deletions front-end/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions front-end/src/api/get-homeboard-students.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { httpMock } from "shared/helpers/http-mock"
import { addIfNotExist, LocalStorageKey } from "shared/helpers/local-storage"
import { ApiResponse } from "shared/interfaces/http.interface"
import { Person } from "shared/models/person"

export async function getHomeboardStudents(): Promise<ApiResponse<{ students: Person[] }>> {
import { SearchParams } from "shared/interfaces/search.interface"
export async function getHomeboardStudents(params: SearchParams): Promise<ApiResponse<{ students: Person[] }>> {
try {
await httpMock({ randomFailure: true })
return {
success: true,
students: addIfNotExist(LocalStorageKey.students, generateStudents(14)),
students: generateStudents(14, params),
}
} catch (error) {
return {
Expand Down
30 changes: 28 additions & 2 deletions front-end/src/shared/helpers/data-generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,32 @@ export function generateStudent(id: number) {
}
}

export function generateStudents(number: number) {
return generateRange(number).map((_, id) => generateStudent(id + 1))
function sortingByOrder(key: string, items: any) {
let keyName = key ? key : "first_name"
return items.sort(function (a: any, b: any) {
const nameA = a[keyName].toUpperCase() // ignore upper and lowercase
const nameB = b[keyName].toUpperCase() // ignore upper and lowercase
if (nameA < nameB) {
return -1
}
if (nameA > nameB) {
return 1
}
return 0
})
}

export function generateStudents(number: number, params: any) {
let data: any = generateRange(number).map((_, id) => generateStudent(id + 1))
if (params && params.sortByName) {
let sortData = sortingByOrder(params.sortByName, data)
data = params.sortBy === "desc" ? sortData.reverse() : sortData
}
if (params && params.text) {
let searchData = data.filter(
(item: any) => item.first_name.toLowerCase().indexOf(params.text.toLowerCase()) > -1 || item.last_name.toLowerCase().indexOf(params.text.toLowerCase()) > -1
)
data = searchData
}
return data.length > 0 ? data : []
}
6 changes: 3 additions & 3 deletions front-end/src/shared/hooks/use-api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { RollInput } from "shared/models/roll"
import { getHomeboardStudents } from "api/get-homeboard-students"
import { getActivities } from "api/get-activities"
import { saveActiveRoll } from "api/save-active-roll"

import { SearchParams } from "shared/interfaces/search.interface"
interface Options {
url: Endpoint
initialLoadState?: LoadState
}

export function useApi<ReturnType = {}>({ url, initialLoadState = "loading" }: Options) {
const [state, dispatch] = useReducer(stateReducer<ReturnType>(), { data: undefined, loadState: initialLoadState, error: undefined })
const callApi = useCallback(
async (params?: object) => {
dispatch({ type: "loading" })

function process(result: ApiResponse<ReturnType>) {
if (result.success) {
dispatch({ type: "success", result: result })
Expand All @@ -25,7 +25,7 @@ export function useApi<ReturnType = {}>({ url, initialLoadState = "loading" }: O

switch (url) {
case "get-homeboard-students":
return getHomeboardStudents().then(process)
return getHomeboardStudents(params as SearchParams).then(process)
case "get-activities":
return getActivities().then(process)
case "save-roll":
Expand Down
5 changes: 5 additions & 0 deletions front-end/src/shared/interfaces/search.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface SearchParams {
sortBy: string
sortByName: string
text: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,30 @@ import Button from "@material-ui/core/Button"
import { BorderRadius, Spacing } from "shared/styles/styles"
import { RollStateList } from "staff-app/components/roll-state/roll-state-list.component"

export type ActiveRollAction = "filter" | "exit"
export type ActiveRollAction = "complete" | "exit"
interface Props {
isActive: boolean
onItemClick: (action: ActiveRollAction, value?: string) => void
roleStatus: any
}

export const ActiveRollOverlay: React.FC<Props> = (props) => {
const { isActive, onItemClick } = props
const { isActive, onItemClick, roleStatus } = props
let presentLength = Object.keys(roleStatus).filter((key) => {
if (roleStatus[key] === "present") {
return key
}
}).length
let lateLength = Object.keys(roleStatus).filter((key) => {
if (roleStatus[key] === "late") {
return key
}
}).length
let absentLength = Object.keys(roleStatus).filter((key) => {
if (roleStatus[key] === "absent") {
return key
}
}).length

return (
<S.Overlay isActive={isActive}>
Expand All @@ -20,17 +36,17 @@ export const ActiveRollOverlay: React.FC<Props> = (props) => {
<div>
<RollStateList
stateList={[
{ type: "all", count: 0 },
{ type: "present", count: 0 },
{ type: "late", count: 0 },
{ type: "absent", count: 0 },
{ type: "all", count: Object.keys(roleStatus).length },
{ type: "present", count: presentLength },
{ type: "late", count: lateLength || 0 },
{ type: "absent", count: absentLength || 0 },
]}
/>
<div style={{ marginTop: Spacing.u6 }}>
<Button color="inherit" onClick={() => onItemClick("exit")}>
Exit
</Button>
<Button color="inherit" style={{ marginLeft: Spacing.u2 }} onClick={() => onItemClick("exit")}>
<Button color="inherit" style={{ marginLeft: Spacing.u2 }} onClick={() => onItemClick("complete")}>
Complete
</Button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { RollStateSwitcher } from "staff-app/components/roll-state/roll-state-sw
interface Props {
isRollMode?: boolean
student: Person
onStateChange: any
}
export const StudentListTile: React.FC<Props> = ({ isRollMode, student }) => {
export const StudentListTile: React.FC<Props> = ({ isRollMode, student, onStateChange }) => {
return (
<S.Container>
<S.Avatar url={Images.avatar}></S.Avatar>
Expand All @@ -19,7 +20,7 @@ export const StudentListTile: React.FC<Props> = ({ isRollMode, student }) => {
</S.Content>
{isRollMode && (
<S.Roll>
<RollStateSwitcher />
<RollStateSwitcher onStateChange={(e) => onStateChange(student.id, e)} />
</S.Roll>
)}
</S.Container>
Expand Down
51 changes: 43 additions & 8 deletions front-end/src/staff-app/daily-care/home-board.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,63 @@ import { ActiveRollOverlay, ActiveRollAction } from "staff-app/components/active
export const HomeBoardPage: React.FC = () => {
const [isRollMode, setIsRollMode] = useState(false)
const [getStudents, data, loadState] = useApi<{ students: Person[] }>({ url: "get-homeboard-students" })
const [sortBy, setSortBy] = useState("asc")
const [sortByName, setSortByName] = useState("first_name")
const [text, setText] = useState("")
const [roleStatus, setRoleStatus] = useState({})

useEffect(() => {
void getStudents()
}, [getStudents])
void getStudents({ sortBy, sortByName, text })
}, [sortBy, sortByName, text])

const onToolbarAction = (action: ToolbarAction) => {
if (action === "roll") {
setIsRollMode(true)
}
if (action === "sort") {
setSortBy(sortBy === "asc" ? "desc" : "asc")
}
}

const onChangeSortName = (value: string) => {
setSortByName(value)
}

const onActiveRollAction = (action: ActiveRollAction) => {
if (action === "exit") {
setIsRollMode(false)
}
if (action === "complete") {
setIsRollMode(false)
}
}

const onChangeText = (value: string) => {
setText(value)
}

const onStateChange = (id: number, value: string) => {
let status: any = { ...roleStatus }
status[id] = value
console.log(value)
setRoleStatus(status)
}

return (
<>
<S.PageContainer>
<Toolbar onItemClick={onToolbarAction} />
<Toolbar onItemClick={onToolbarAction} sortByName={sortByName} onChangeSortName={onChangeSortName} onChangeText={onChangeText} text={text} />

{loadState === "loading" && (
<CenteredContainer>
<FontAwesomeIcon icon="spinner" size="2x" spin />
</CenteredContainer>
)}

{loadState === "loaded" && data?.students && (
{loadState === "loaded" && data?.students && data?.students?.length > 0 && (
<>
{data.students.map((s) => (
<StudentListTile key={s.id} isRollMode={isRollMode} student={s} />
<StudentListTile key={s.id} isRollMode={isRollMode} student={s} onStateChange={onStateChange} />
))}
</>
)}
Expand All @@ -55,21 +80,31 @@ export const HomeBoardPage: React.FC = () => {
</CenteredContainer>
)}
</S.PageContainer>
<ActiveRollOverlay isActive={isRollMode} onItemClick={onActiveRollAction} />
<ActiveRollOverlay isActive={isRollMode} onItemClick={onActiveRollAction} roleStatus={roleStatus} />
</>
)
}

type ToolbarAction = "roll" | "sort"
interface ToolbarProps {
onItemClick: (action: ToolbarAction, value?: string) => void
sortByName: string
onChangeSortName: (value: string) => void
onChangeText: (value: string) => void
text: string
}
const Toolbar: React.FC<ToolbarProps> = (props) => {
const { onItemClick } = props
const { onItemClick, sortByName, onChangeSortName, onChangeText, text } = props
return (
<S.ToolbarContainer>
<div onClick={() => onItemClick("sort")}>First Name</div>
<div>Search</div>
<div>
<select value={sortByName} onChange={(e) => onChangeSortName(e.target.value)}>
<option value="first_name">First Name</option>
<option value="last_name">Last Name</option>
</select>
<input type="text" placeholder={"Please write for search"} value={text} onChange={(e) => onChangeText(e.target.value)} />
</div>
<S.Button onClick={() => onItemClick("roll")}>Start Roll</S.Button>
</S.ToolbarContainer>
)
Expand Down