Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: teacher onboarding #83

Merged
merged 14 commits into from
Jan 17, 2025
Merged
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 })

Check warning on line 22 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L21-L22

Added lines #L21 - L22 were not covered by tests

const styles = pdf.StyleSheet.create({

Check warning on line 24 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L24

Added line #L24 was not covered by tests
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 (

Check warning on line 46 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L46

Added line #L46 was not covered by tests
<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}>

Check warning on line 53 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L52-L53

Added lines #L52 - L53 were not covered by tests
<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)

Check warning on line 86 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L85-L86

Added lines #L85 - L86 were not covered by tests

const downloadPdf = async (): Promise<void> => {
try {
const blob = await pdf

Check warning on line 90 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L88-L90

Added lines #L88 - L90 were not covered by tests
.pdf(<PDF classId={classId} students={students} />)
.toBlob()

const url = URL.createObjectURL(blob)

Check warning on line 94 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L94

Added line #L94 was not covered by tests

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

Check warning on line 98 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L97-L98

Added lines #L97 - L98 were not covered by tests
}

URL.revokeObjectURL(url)

Check warning on line 101 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L101

Added line #L101 was not covered by tests
} catch (error) {
console.error(error)

Check warning on line 103 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L103

Added line #L103 was not covered by tests
}
}

return (

Check warning on line 107 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L107

Added line #L107 was not covered by tests
<>
<Button
endIcon={<PrintIcon />}
onClick={() => {
void downloadPdf()

Check warning on line 112 in src/components/PrintPasswordReminderCardsButton.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintPasswordReminderCardsButton.tsx#L111-L112

Added lines #L111 - L112 were not covered by tests
}}
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" }}>

Check warning on line 16 in src/components/PrintStudentCredentialsNotification.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/PrintStudentCredentialsNotification.tsx#L15-L16

Added lines #L15 - L16 were not covered by tests
<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