Skip to content

Commit dc243d0

Browse files
authored
Merge pull request #21 from CS3219-AY2526Sem1/user-page
Implement user page and history
2 parents a0da90d + 19dc9b8 commit dc243d0

File tree

10 files changed

+329
-6
lines changed

10 files changed

+329
-6
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
.logo {
2+
height: 30px;
3+
cursor: pointer;
4+
}
5+
6+
.header {
7+
height: 56px;
8+
margin-bottom: 20px;
9+
background-color: var(--mantine-color-body);
10+
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
11+
padding: 0 16px;
12+
}
13+
14+
.inner {
15+
height: 56px;
16+
display: flex;
17+
justify-content: space-between;
18+
align-items: center;
19+
padding: 0;
20+
}
21+
22+
.link {
23+
display: block;
24+
line-height: 1;
25+
padding: 8px 12px;
26+
border-radius: var(--mantine-radius-sm);
27+
text-decoration: none;
28+
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
29+
font-size: var(--mantine-font-size-sm);
30+
font-weight: 500;
31+
32+
@mixin hover {
33+
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
34+
}
35+
36+
[data-mantine-color-scheme] &[data-active] {
37+
background-color: var(--mantine-color-blue-filled);
38+
color: var(--mantine-color-white);
39+
}
40+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// With reference from official Mantine documentation
2+
// https://ui.mantine.dev/category/headers/
3+
4+
import { Container, Group, Text } from "@mantine/core";
5+
import { useNavigate } from "react-router";
6+
import classes from "./header.module.css";
7+
import logo from "../../assets/images/logo.svg";
8+
9+
export default function Header() {
10+
const navigate = useNavigate();
11+
12+
return (
13+
<header className={classes.header}>
14+
<Container size={"md"} className={classes.inner}>
15+
<Group>
16+
<img
17+
src={logo}
18+
alt="PeerPrep Logo"
19+
className={classes.logo}
20+
onClick={() => navigate("/")}
21+
/>
22+
</Group>
23+
<Group gap={5}>
24+
<Text>NorbertLoh</Text>
25+
</Group>
26+
</Container>
27+
</header>
28+
);
29+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Card, Text } from "@mantine/core";
2+
3+
export default function StatsCard({
4+
title,
5+
stat,
6+
color,
7+
}: {
8+
title: string;
9+
stat: string;
10+
color: string;
11+
}) {
12+
return (
13+
<Card shadow="sm" padding="lg">
14+
<Text fw={700} ta="center" c="white">{stat}</Text>
15+
<Text c={color} ta="center">{title}</Text>
16+
</Card>
17+
);
18+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.cell {
2+
width: 150px;
3+
text-align: right;
4+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Button, Card, Divider, Table, Text, Pagination, Group } from "@mantine/core";
2+
import classes from "./table.module.css";
3+
4+
export type InterviewHistory = {
5+
question: string;
6+
completionDate: string;
7+
difficulty: string;
8+
topic: string;
9+
language: string;
10+
};
11+
12+
export default function HistoryTable({ data }: { data: InterviewHistory[] }) {
13+
const rows = data.map((row) => (
14+
<Table.Tr key={row.question}>
15+
<Table.Td>{row.question}</Table.Td>
16+
<Table.Td ta="right">{row.completionDate}</Table.Td>
17+
<Table.Td ta="right">{row.difficulty}</Table.Td>
18+
<Table.Td ta="right">{row.topic}</Table.Td>
19+
<Table.Td ta="right">{row.language}</Table.Td>
20+
<Table.Td ta="right" style={{ width: 100 }}>
21+
<Button>View</Button>
22+
</Table.Td>
23+
</Table.Tr>
24+
));
25+
return (
26+
<Card shadow="sm" padding="lg">
27+
<Text fw={1000} size="xl" c="white" mb={"xs"}>
28+
Interviews
29+
</Text>
30+
<Divider />
31+
<Table.ScrollContainer minWidth={500}>
32+
<Table c={"white"} highlightOnHover>
33+
<Table.Thead>
34+
<Table.Tr>
35+
<Table.Th>Question</Table.Th>
36+
<Table.Th className={classes.cell}>Completion Date</Table.Th>
37+
<Table.Th className={classes.cell}>Difficulty</Table.Th>
38+
<Table.Th className={classes.cell}>Topic</Table.Th>
39+
<Table.Th className={classes.cell}>Language</Table.Th>
40+
<Table.Th className={classes.cell}></Table.Th>
41+
</Table.Tr>
42+
</Table.Thead>
43+
<Table.Tbody>{rows}</Table.Tbody>
44+
</Table>
45+
</Table.ScrollContainer>
46+
<Group justify="center">
47+
<Pagination total={5} siblings={3} defaultValue={1} />
48+
49+
</Group>
50+
</Card>
51+
);
52+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
Grid,
3+
Button,
4+
useMantineTheme,
5+
} from "@mantine/core";
6+
7+
import StatsCard from "../components/statscard";
8+
import HistoryTable from "../components/table/table";
9+
import type {InterviewHistory} from "../components/table/table";
10+
11+
import { useState } from "react";
12+
13+
export function meta() {
14+
return [
15+
{ title: "PeerPrep - Homepage" },
16+
{ name: "description", content: "Welcome to PeerPrep!" },
17+
];
18+
}
19+
20+
export default function Userpage() {
21+
const theme = useMantineTheme();
22+
23+
const [data, ] = useState<InterviewHistory[]>([
24+
{
25+
question: "Two Sum",
26+
completionDate: "2024-10-01",
27+
difficulty: "Easy",
28+
topic: "Array",
29+
language: "JavaScript",
30+
},
31+
]);
32+
33+
return (
34+
<Grid>
35+
<Grid.Col span={12}>
36+
<Grid gutter="md" align="center">
37+
<Grid.Col span={{ base: 6, md: 2 }}>
38+
<StatsCard
39+
title="Interviews"
40+
stat="1,234"
41+
color={theme.colors.gray[0]}
42+
/>
43+
</Grid.Col>
44+
<Grid.Col span={{ base: 6, md: 2 }}>
45+
<StatsCard
46+
title="Easy"
47+
stat="1,234"
48+
color={theme.colors.green[5]}
49+
/>
50+
</Grid.Col>
51+
<Grid.Col span={{ base: 6, md: 2 }}>
52+
<StatsCard
53+
title="Medium"
54+
stat="1,234"
55+
color={theme.colors.yellow[5]}
56+
/>
57+
</Grid.Col>
58+
<Grid.Col span={{ base: 6, md: 2 }}>
59+
<StatsCard title="Hard" stat="1,234" color={theme.colors.red[5]} />
60+
</Grid.Col>
61+
<Grid.Col span={{ base: 12, md: 1 }} offset={{ md: 3 }}>
62+
<Button fullWidth>Queue Up</Button>
63+
</Grid.Col>
64+
</Grid>
65+
</Grid.Col>
66+
<Grid.Col span={12}>
67+
<HistoryTable
68+
data={data}
69+
/>
70+
</Grid.Col>
71+
</Grid>
72+
);
73+
}

frontend/peerprep/app/root.tsx

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@ import {
55
Outlet,
66
Scripts,
77
ScrollRestoration,
8+
useLocation,
89
} from "react-router";
910

10-
import '@mantine/core/styles.css';
11-
import { createTheme, MantineProvider } from '@mantine/core';
11+
import "@mantine/core/styles.css";
12+
import {
13+
createTheme,
14+
MantineProvider,
15+
Container,
16+
Button,
17+
Input,
18+
} from "@mantine/core";
1219

1320
import type { Route } from "./+types/root";
1421
import "./app.css";
22+
import Header from "./components/header/header";
1523

1624
export const links: Route.LinksFunction = () => [
1725
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
@@ -28,6 +36,92 @@ export const links: Route.LinksFunction = () => [
2836

2937
const theme = createTheme({
3038
/** mantine theme overrides */
39+
colors: {
40+
"brand-yellow": [
41+
"#fff9df",
42+
"#fff2ca",
43+
"#ffe399",
44+
"#ffd463",
45+
"#ffc736",
46+
"#ffc01e",
47+
"#ffba02",
48+
"#e4a300",
49+
"#cb9100",
50+
"#af7c00",
51+
],
52+
"custom-gray": [
53+
"#f5f5f4",
54+
"#e7e7e7",
55+
"#cdcdcd",
56+
"#b2b2b2",
57+
"#9a9a9a",
58+
"#8b8b8b",
59+
"#848484",
60+
"#717171",
61+
"#646464",
62+
"#343231",
63+
],
64+
green: [
65+
"#e5ffe5",
66+
"#cefecf",
67+
"#9ffa9f",
68+
"#6bf76b",
69+
"#48f548",
70+
"#24f324",
71+
"#0df212",
72+
"#00d701",
73+
"#00c000",
74+
"#00a600",
75+
],
76+
77+
yellow: [
78+
"#fff9df",
79+
"#fff2ca",
80+
"#ffe399",
81+
"#ffd463",
82+
"#ffc736",
83+
"#ffc01e",
84+
"#ffba02",
85+
"#e4a300",
86+
"#cb9100",
87+
"#af7c00",
88+
],
89+
90+
red: [
91+
"#ffe7e8",
92+
"#ffcece",
93+
"#ff9b9b",
94+
"#ff6464",
95+
"#fe3736",
96+
"#fe1b19",
97+
"#ff0000",
98+
"#e40000",
99+
"#cb0000",
100+
"#b20000",
101+
],
102+
},
103+
104+
components: {
105+
Button: Button.extend({
106+
defaultProps: {
107+
variant: "filled",
108+
color: "brand-yellow",
109+
c: "custom-gray.9",
110+
},
111+
}),
112+
113+
Input: Input.extend({}),
114+
115+
InputWrapper: Input.Wrapper.extend({
116+
classNames: {
117+
label: "text-white",
118+
error: "text-red-500",
119+
},
120+
}),
121+
},
122+
123+
primaryColor: "brand-yellow",
124+
primaryShade: { light: 6, dark: 6 },
31125
});
32126

33127
export function Layout({ children }: { children: React.ReactNode }) {
@@ -49,9 +143,17 @@ export function Layout({ children }: { children: React.ReactNode }) {
49143
}
50144

51145
export default function App() {
146+
const location = useLocation();
147+
const linksWithHeader = ["/user"];
148+
149+
const isHeader = () => {
150+
return linksWithHeader.includes(location.pathname);
151+
};
152+
52153
return (
53-
<MantineProvider theme={theme}>
54-
{<Outlet />}
154+
<MantineProvider theme={theme} defaultColorScheme="dark">
155+
{isHeader() && <Header />}
156+
<Container fluid>{<Outlet />}</Container>
55157
</MantineProvider>
56158
);
57159
}

frontend/peerprep/app/routes.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1-
import { type RouteConfig, index } from "@react-router/dev/routes";
1+
import { type RouteConfig, index, route } from "@react-router/dev/routes";
22

3-
export default [index("routes/home.tsx")] satisfies RouteConfig;
3+
export default [
4+
index("routes/home.tsx"),
5+
route("login", "pages/login.tsx"),
6+
route("signup", "pages/signup.tsx"),
7+
route("user", "pages/userpage.tsx"),
8+
] satisfies RouteConfig;

services/collaboration-service/app/routers/__init__.py

Whitespace-only changes.

services/question-service/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)