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

Portal frontend#8 #10

Merged
merged 13 commits into from
Jul 12, 2024
Merged
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
29 changes: 29 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
VITE_API_BASE_URL=http://localhost:8000/api/
VITE_SERVICE_NAME=portal

# Links external sites.
VITE_LINK_OPEN_VERIFY_EMAIL_IN_GMAIL="https://mail.google.com/mail/#search/from%3Ano-reply%40info.codeforlife.education+subject%3AEmail+Verification"
VITE_LINK_OPEN_VERIFY_EMAIL_IN_OUTLOOK=https://outlook.live.com/mail/
VITE_LINK_FEMALE_GRADUATES_IN_CS=https://www.wisecampaign.org.uk/core-stem-graduates-2019/

# TODO: determine which of these we need.
# REACT_APP_CONTAINER_MAX_WIDTH=lg
# REACT_APP_FACEBOOK_HREF=https://www.facebook.com/codeforlifeuk
# REACT_APP_TWITTER_HREF=https://twitter.com/codeforlifeuk
# REACT_APP_INSTAGRAM_HREF=https://www.instagram.com/codeforlife_uk/
# REACT_APP_OCADO_GROUP_HREF=https://www.ocadogroup.com/our-responsible-business/corporate-responsibility/skills-for-the-future
# REACT_APP_PORTAL_GITHUB_HREF=https://github.com/ocadotechnology/codeforlife-portal
# REACT_APP_CFL_DOCS_HREF=https://docs.codeforlife.education/
# REACT_APP_PRIMARY_RESOURCE_HREF=https://code-for-life.gitbook.io/code-club-resources/
# REACT_APP_PYTHON_RESOURCE_HREF=https://code-for-life.gitbook.io/code-club-resources-intermediate/
# REACT_APP_IDEAS_BOX_HREF=https://docs.google.com/forms/d/e/1FAIpQLSclasSZCb7s26Yax3KZuXIFhLjMhGK591WPvht0BkfjSiQR1w/viewform
# REACT_APP_INDEPENDENT_BEGINNER_HREF=https://code-for-life.gitbook.io/independent-student-resources/beginner/
# REACT_APP_INDEPENDENT_INTERMEDIATE_HREF=https://code-for-life.gitbook.io/independent-student-resources/intermediate/
# REACT_APP_INDEPENDENT_ADVANCED_HREF=https://code-for-life.gitbook.io/independent-student-resources/advanced/
# REACT_APP_API_BASE_URL=http://localhost:8000/api/
# REACT_APP_RAPID_ROUTER_YOUTUBE_VIDEO_SRC=https://www.youtube-nocookie.com/embed/w0Pw_XikQSs
# REACT_APP_KURONO_YOUTUBE_VIDEO_SRC=https://www.youtube-nocookie.com/embed/m-JYukDZlL8
# REACT_APP_BLOCKLY_GUIDE_SRC=https://docs.codeforlife.education/rapid-router/blockly-guide
# REACT_APP_TEACHER_RESOURCES_YOUTUBE_VIDEO_SRC=https://www.youtube-nocookie.com/embed/tM5nKPYlz74
# REACT_APP_RR_FOR_TEACHER_YOUTUBE_VIDEO_SRC=https://www.youtube-nocookie.com/embed/hv0fM0twrOE
# REACT_APP_KURONO_FOR_TEACHER_YOUTUBE_VIDEO_SRC=https://www.youtube-nocookie.com/embed/6iiksCtIIGA
# REACT_APP_INTRO_TO_CODING_ENGLAND=https://code-for-life.gitbook.io/teaching-resources/rapid-router-resources/introduction-to-coding-england
# REACT_APP_INTRO_TO_CODING_SCOTLAND=https://code-for-life.gitbook.io/teaching-resources/rapid-router-resources/introduction-to-coding-scotland
# REACT_APP_KURONO_AND_CURRICULUM=https://code-for-life.gitbook.io/teaching-resources/v/kurono-teaching-resources/teacher-guides/kurono-and-the-national-curriculum-for-computing
# REACT_APP_RR_TEACHING_RESOURCE=https://code-for-life.gitbook.io/teaching-resources/rapid-router-resources/welcome-to-rapid-router
# REACT_APP_KURONO_TEACHING_RESOURCE=https://code-for-life.gitbook.io/teaching-resources/v/kurono-teaching-resources/
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"//": "🚫 Don't add `dependencies` below that are inherited from the CFL package.",
"dependencies": {
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v2.1.0"
"codeforlife": "github:ocadotechnology/codeforlife-package-javascript#v2.1.1"
},
"//": "✅ Do add `devDependencies` below that are `peerDependencies` in the CFL package.",
"devDependencies": {
Expand Down
16 changes: 6 additions & 10 deletions src/api/authFactor.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { urls, type AuthFactor } from "codeforlife/api"
import {
getReadAuthFactorEndpoints,
urls,
type AuthFactor,
} from "codeforlife/api"
import {
buildUrl,
tagData,
type CreateArg,
type CreateResult,
type DestroyArg,
type DestroyResult,
type ListArg,
type ListResult,
} from "codeforlife/utils/api"

import api from "."

const authFactorApi = api.injectEndpoints({
endpoints: build => ({
...getReadAuthFactorEndpoints(build),
createAuthFactor: build.mutation<
CreateResult<AuthFactor>,
CreateArg<AuthFactor, "type">
Expand All @@ -31,13 +34,6 @@ const authFactorApi = api.injectEndpoints({
}),
invalidatesTags: tagData("AuthFactor"),
}),
listAuthFactors: build.query<ListResult<AuthFactor, "type">, ListArg>({
query: search => ({
url: buildUrl(urls.authFactor.list, { search }),
method: "GET",
}),
providesTags: tagData("AuthFactor"),
}),
}),
})

Expand Down
41 changes: 2 additions & 39 deletions src/api/klass.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { urls, type Class } from "codeforlife/api"
import { getReadClassEndpoints, urls, type Class } from "codeforlife/api"
import {
buildUrl,
tagData,
type CreateArg,
type CreateResult,
type DestroyArg,
type DestroyResult,
type ListArg,
type ListResult,
type RetrieveArg,
type RetrieveResult,
type UpdateArg,
type UpdateResult,
} from "codeforlife/utils/api"
Expand All @@ -18,6 +14,7 @@ import api from "."

const classApi = api.injectEndpoints({
endpoints: build => ({
...getReadClassEndpoints(build),
createClass: build.mutation<
CreateResult<Class>,
CreateArg<
Expand Down Expand Up @@ -54,40 +51,6 @@ const classApi = api.injectEndpoints({
}),
invalidatesTags: tagData("Class"),
}),
retrieveClass: build.query<
RetrieveResult<
Class,
| "name"
| "read_classmates_data"
| "receive_requests_until"
| "school"
| "teacher"
>,
RetrieveArg<Class>
>({
query: id => ({
url: buildUrl(urls.class.detail, { url: { id } }),
method: "GET",
}),
providesTags: tagData("Class"),
}),
listClasses: build.query<
ListResult<
Class,
| "name"
| "read_classmates_data"
| "receive_requests_until"
| "school"
| "teacher"
>,
ListArg
>({
query: search => ({
url: buildUrl(urls.class.list, { search }),
method: "GET",
}),
providesTags: tagData("Class"),
}),
}),
})

Expand Down
15 changes: 2 additions & 13 deletions src/api/school.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { urls, type School } from "codeforlife/api"
import { getReadSchoolEndpoints, urls, type School } from "codeforlife/api"
import {
buildUrl,
tagData,
type CreateArg,
type CreateResult,
type RetrieveArg,
type RetrieveResult,
type UpdateArg,
type UpdateResult,
} from "codeforlife/utils/api"
Expand All @@ -14,16 +12,7 @@ import api from "."

const schoolApi = api.injectEndpoints({
endpoints: build => ({
retrieveSchool: build.query<
RetrieveResult<School, "name" | "country" | "uk_county">,
RetrieveArg<School>
>({
query: id => ({
url: buildUrl(urls.school.detail, { url: { id } }),
method: "GET",
}),
providesTags: tagData("School"),
}),
...getReadSchoolEndpoints(build),
createSchool: build.mutation<
CreateResult<School>,
CreateArg<School, "name", "country" | "uk_county">
Expand Down
47 changes: 2 additions & 45 deletions src/api/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { urls, type User } from "codeforlife/api"
import { getReadUserEndpoints, urls, type User } from "codeforlife/api"
import {
buildUrl,
tagData,
Expand All @@ -7,10 +7,6 @@ import {
type CreateResult,
type DestroyArg,
type DestroyResult,
type ListArg,
type ListResult,
type RetrieveArg,
type RetrieveResult,
type UpdateArg,
type UpdateResult,
} from "codeforlife/utils/api"
Expand All @@ -19,6 +15,7 @@ import api from "."

const userApi = api.injectEndpoints({
endpoints: build => ({
...getReadUserEndpoints(build),
handleJoinClassRequest: build.mutation<
UpdateResult<User>,
UpdateArg<User, never, "first_name", { accept: boolean }>
Expand Down Expand Up @@ -101,46 +98,6 @@ const userApi = api.injectEndpoints({
body,
}),
}),
retrieveUser: build.query<
RetrieveResult<
User,
| "first_name"
| "last_name"
| "email"
| "is_active"
| "date_joined"
| "requesting_to_join_class"
| "student"
| "teacher"
>,
RetrieveArg<User>
>({
query: id => ({
url: buildUrl(urls.user.detail, { url: { id } }),
method: "GET",
}),
providesTags: tagData("User"),
}),
listUsers: build.query<
ListResult<
User,
| "first_name"
| "last_name"
| "email"
| "is_active"
| "date_joined"
| "requesting_to_join_class"
| "student"
| "teacher"
>,
ListArg<{ students_in_class: string }>
>({
query: search => ({
url: buildUrl(urls.user.list, { search }),
method: "GET",
}),
providesTags: tagData("User"),
}),
}),
})

Expand Down
Binary file added src/images/dashboard_educate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/dashboard_play.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/icon_controller.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/icon_free.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/icon_globe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/icon_piechart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/reuben.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/rob.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/sian.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions src/pages/home/AboutUs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ChevronRight as ChevronRightIcon } from "@mui/icons-material"
import { Unstable_Grid2 as Grid, Stack, Typography } from "@mui/material"
import { type FC } from "react"

import { Image } from "codeforlife/components"
import { Link, LinkButton } from "codeforlife/components/router"

import ControllerIcon from "../../images/icon_controller.png"
import TicketIcon from "../../images/icon_free.png"
import GlobeIcon from "../../images/icon_globe.png"
import PieChartIcon from "../../images/icon_piechart.png"
import { paths } from "../../router"

const Column: FC<{
img: { alt: string; src: string }
children: React.ReactNode
}> = ({ img, children }) => (
<Grid xs={12} sm={6} md={3}>
<Stack alignItems="center">
<Image alt={img.alt} src={img.src} maxWidth="200px" />
{children}
</Stack>
</Grid>
)

export interface AboutUsProps {}

const AboutUs: FC<AboutUsProps> = () => (
<Grid container columnSpacing={2}>
<Grid xs={12}>
<Typography variant="h4" textAlign="center">
Giving everyone the ability to shape technology&apos;s future
</Typography>
</Grid>
<Column img={{ alt: "pie chart", src: PieChartIcon }}>
<Typography textAlign="center">
Just 16% of university computer science graduates (2018/19) in the UK
were women
<Link
to={import.meta.env.VITE_LINK_FEMALE_GRADUATES_IN_CS}
target="_blank"
>
*
</Link>
, we want to change that.
</Typography>
</Column>
<Column img={{ alt: "game controller", src: ControllerIcon }}>
<Typography textAlign="center">
Gamification helps children learn whilst having fun!
</Typography>
</Column>
<Column img={{ alt: "free ticket", src: TicketIcon }}>
<Typography textAlign="center">
That&apos;s right, free forever: our gift to you! We&apos;re also Open
Source.
</Typography>
</Column>
<Column img={{ alt: "earth", src: GlobeIcon }}>
{/* TODO: add more accurate figure */}
<Typography textAlign="center">
Code for Life has over 350,000 registered users across the world.
</Typography>
</Column>
<Grid xs={12} display="flex" justifyContent="end">
<LinkButton to={paths.aboutUs._} endIcon={<ChevronRightIcon />}>
About us
</LinkButton>
</Grid>
</Grid>
)

export default AboutUs
31 changes: 31 additions & 0 deletions src/pages/home/CodingClubs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ChevronRight as ChevronRightIcon } from "@mui/icons-material"
import { Stack, Typography } from "@mui/material"
import { type FC } from "react"

import { LinkButton } from "codeforlife/components/router"

import { paths } from "../../router"

export interface CodingClubsProps {}

const CodingClubs: FC<CodingClubsProps> = () => (
<Stack>
<Typography variant="h3" textAlign="center">
Want to run a Code for Life coding club?
</Typography>
<Typography>
Take a look at our two club packs that we have put together using our
Rapid Router resources. These are fast-paced, session based clubs that can
be run by anyone keen to help people learn to code. There are guides and
resource links with printable cerificates for those that complete the
course.
</Typography>
<Stack direction="row" justifyContent="end">
<LinkButton to={paths.codingClubs._} endIcon={<ChevronRightIcon />}>
Find out more
</LinkButton>
</Stack>
</Stack>
)

export default CodingClubs
40 changes: 40 additions & 0 deletions src/pages/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useTheme } from "@mui/material"
import { type FC } from "react"

import * as page from "codeforlife/components/page"
import { useLocation } from "codeforlife/hooks"

import AboutUs from "./AboutUs"
import CodingClubs from "./CodingClubs"
import Quotes from "./Quotes"
import TargetAudience from "./TargetAudience"

const Home: FC = () => {
const theme = useTheme()
const { state } = useLocation<{ signUpSuccess: boolean }>()

return (
<page.Page>
{state?.signUpSuccess !== undefined && (
<page.Notification error={!state.signUpSuccess}>
{state.signUpSuccess
? "Thank you for signing up! 🎉"
: "Invalid email address. Please try again."}
</page.Notification>
)}
{/* Special case: un-contained page section */}
<TargetAudience />
<page.Section>
<AboutUs />
</page.Section>
<page.Section boxProps={{ bgcolor: theme.palette.info.main }}>
<Quotes />
</page.Section>
<page.Section>
<CodingClubs />
</page.Section>
</page.Page>
)
}

export default Home
Loading
Loading