Skip to content

Commit

Permalink
feat: teacher onboarding (#83)
Browse files Browse the repository at this point in the history
* quick save

* quick save

* quick save

* fixes

* fix: simplify

* fix: refetchOnMountOrArgChange

* new cfl package

* reuse create class form

* fix: print credentials pdf notification

* fix: button styles

* unique names

* fix: install new cfl package

* feedback

* small fix
  • Loading branch information
SKairinos authored Jan 17, 2025
1 parent e2a87e7 commit 275e94b
Show file tree
Hide file tree
Showing 21 changed files with 1,581 additions and 1,193 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
],
"dependencies": {
"@react-pdf/renderer": "^4.0.0",
"codeforlife": "2.6.3",
"codeforlife": "2.6.5",
"crypto-js": "^4.2.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/api/klass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type {
RetrieveClassResult,
}

export type CreateClassResult = CreateResult<Class>
export type CreateClassResult = CreateResult<Class, "name">
export type CreateClassArg = CreateArg<
Class,
"name" | "read_classmates_data",
Expand Down
125 changes: 125 additions & 0 deletions src/components/PrintPasswordReminderCardsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as pdf from "@react-pdf/renderer"
import { Button, type ButtonProps } from "@mui/material"
import { type FC, useRef } from "react"
import { type Student, type User } from "codeforlife/api"
import { Print as PrintIcon } from "@mui/icons-material"
import { generatePath } from "react-router-dom"

import CflLogoImage from "../images/logo_cfl.png"
import { makeAutoLoginLink } from "../utils/student"
import { paths } from "../routes"

interface PDFProps {
classId: string
students: Array<
Pick<Student, "id" | "auto_gen_password"> & {
user: Pick<User, "id" | "first_name" | "password">
}
>
}

const PDF: FC<PDFProps> = ({ classId, students }) => {
const classLoginLink = generatePath(paths.login.student.class._, { classId })

const styles = pdf.StyleSheet.create({
mainView: {
border: "2px solid black",
display: "flex",
flexDirection: "row",
gap: 5,
padding: 10,
},
page: {
padding: 20,
},
text: {
textAlign: "justify",
marginBottom: 5,
fontSize: 12,
},
image: {
width: 85,
height: 70,
},
})

return (
<pdf.Document>
<pdf.Page size="A4" style={styles.page}>
<pdf.Text style={styles.text}>
Please ensure students keep login details in a secure place
</pdf.Text>
{students.map(student => (
<pdf.View key={`${student.user.id}-pdf`} style={styles.mainView}>
<pdf.Image
source={CflLogoImage}
src={CflLogoImage}
style={styles.image}
/>
<pdf.View>
{/*TODO: Improve overall styles for this.*/}
<pdf.Text style={styles.text}>
Directly log in with:{"\n"}
{makeAutoLoginLink(classLoginLink, student)}
</pdf.Text>
<pdf.Text style={styles.text}>
OR class link: {classLoginLink}
</pdf.Text>
<pdf.Text style={styles.text}>
Name: {student.user.first_name} Password:{" "}
{student.user.password}
</pdf.Text>
</pdf.View>
</pdf.View>
))}
</pdf.Page>
</pdf.Document>
)
}

export type PrintPasswordReminderCardsButtonProps = PDFProps &
Omit<ButtonProps, "endIcon" | "onClick" | "className">

const PrintPasswordReminderCardsButton: FC<
PrintPasswordReminderCardsButtonProps
> = ({ classId, students, ...buttonProps }) => {
const linkRef = useRef<HTMLAnchorElement | null>(null)

const downloadPdf = async (): Promise<void> => {
try {
const blob = await pdf
.pdf(<PDF classId={classId} students={students} />)
.toBlob()

const url = URL.createObjectURL(blob)

if (linkRef.current) {
linkRef.current.href = url
linkRef.current.click()
}

URL.revokeObjectURL(url)
} catch (error) {
console.error(error)
}
}

return (
<>
<Button
endIcon={<PrintIcon />}
onClick={() => {
void downloadPdf()
}}
className="body"
{...buttonProps}
>
Print reminder cards
</Button>
{/* Invisible anchor tag to trigger the download */}
<a ref={linkRef} target="_blank" style={{ display: "none" }}></a>
</>
)
}

export default PrintPasswordReminderCardsButton
32 changes: 32 additions & 0 deletions src/components/PrintStudentCredentialsNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Stack, Typography } from "@mui/material"
import { type FC } from "react"
import { Section } from "codeforlife/components/page"
import { WarningAmber as WarningAmberIcon } from "@mui/icons-material"

import PrintPasswordReminderCardsButton, {
type PrintPasswordReminderCardsButtonProps,
} from "./PrintPasswordReminderCardsButton"

export interface PrintStudentCredentialsNotificationProps
extends PrintPasswordReminderCardsButtonProps {}

const PrintStudentCredentialsNotification: FC<
PrintStudentCredentialsNotificationProps
> = props => (
<Section boxProps={{ bgcolor: "#ffd23b" }} sx={{ paddingY: "5px" }}>
<Stack direction="row" alignItems="center" gap={2}>
<WarningAmberIcon htmlColor="#000" />
<Typography variant="body2" color="#000" mb={0}>
This is the only time you will be able to view this page. You can print
reminder cards or download as a CSV file.
</Typography>
<PrintPasswordReminderCardsButton
{...props}
style={{ marginLeft: "auto" }}
variant="outlined"
/>
</Stack>
</Section>
)

export default PrintStudentCredentialsNotification
Loading

0 comments on commit 275e94b

Please sign in to comment.