Skip to content

Commit

Permalink
Portal frontend#8 (#10)
Browse files Browse the repository at this point in the history
* add git lens

* add page

* get read only endpoints of user objects from js package

* fix paths and routes

* about us page section

* add target audience section

* quotes section

* coding clubs section

* home page

* merge from dev

* new js package

* delete images

* feedback
  • Loading branch information
SKairinos authored Jul 12, 2024
1 parent 3f71cc2 commit 57003fe
Show file tree
Hide file tree
Showing 28 changed files with 557 additions and 161 deletions.
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

0 comments on commit 57003fe

Please sign in to comment.