Skip to content

Commit

Permalink
Merge pull request #70 from CS3219-AY2324S1/feat/submissions
Browse files Browse the repository at this point in the history
feat: add submissions table & update styles
  • Loading branch information
sheimoria authored Nov 13, 2023
2 parents 36882b3 + 3c5ef01 commit 3eebc06
Show file tree
Hide file tree
Showing 59 changed files with 721 additions and 374 deletions.
13 changes: 13 additions & 0 deletions backend/api-gateway/app/types/submission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { z } from "zod";
import { userSchema } from "./user";

export const submissionSchema = z.object({
id: z.number(),
questionId: z.string(),
users: z.array(userSchema),
code: z.string(),
lang: z.string(),
createdAt: z.string(),
});

export type Submission = z.infer<typeof submissionSchema>;
5 changes: 4 additions & 1 deletion backend/api-gateway/app/types/usersService.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { z } from "zod";
import { HTTP_STATUS } from "./http";
import { userSchema } from "./user";
import { submissionSchema } from "./submission";

export const getUserSchema = z.union([
z.object({
status: z.literal(HTTP_STATUS.SUCCESS),
data: z.object({
user: userSchema,
user: userSchema.extend({
submissions: z.array(submissionSchema),
}),
}),
}),
z.object({
Expand Down
11 changes: 11 additions & 0 deletions backend/question-service/server/app/routers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ async def create_question(question: dict):
if collection.find_one({"id": question["id"]}):
raise HTTPException(
status_code=400, detail="Question with the same id already exists.")

# Check if question with the same title already exists
if collection.find_one({"title": question["title"]}):
raise HTTPException(
status_code=400, detail="Question with the same title already exists.")

result = collection.insert_one(question)

question["_id"] = str(question["_id"])
Expand All @@ -41,6 +47,11 @@ async def update_question(question_id: int, updated_data: dict):
# Check if updated_data is empty
if not updated_data:
raise HTTPException(status_code=400, detail="Updated data not provided.")

# Check if question with the same title already exists
if collection.find_one({"title": updated_data["title"]}):
raise HTTPException(
status_code=400, detail="Question with the same title already exists.")

result = collection.update_one({"id": question_id}, {"$set": updated_data})

Expand Down
2 changes: 1 addition & 1 deletion backend/user-service/app/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ model Submission {
id Int @id @default(autoincrement())
questionId String
users User[]
code String
code String @db.LongText
lang String
createdAt DateTime @default(now())
}
Expand Down
10 changes: 8 additions & 2 deletions backend/user-service/app/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@ export const userService = {
delete: (id: Prisma.UserDeleteArgs["where"]["id"]) =>
db.user.delete({ where: { id } }),
findById: (id: Prisma.UserFindUniqueArgs["where"]["id"]) =>
db.user.findUnique({ where: { id } }),
db.user.findUnique({
where: { id },
include: { submissions: { include: { users: true } } },
}),
findByEmail: (email: Prisma.UserFindUniqueArgs["where"]["email"]) =>
db.user.findUnique({ where: { email } }),
db.user.findUnique({
where: { email },
include: { submissions: { include: { users: true } } },
}),
update: (
id: Prisma.UserUpdateArgs["where"]["id"],
data: Prisma.UserUpdateInput
Expand Down
33 changes: 1 addition & 32 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ services:
volumes:
- ./backend/user-service/app:/app:delegated
- /app/node_modules
# depends_on:
# user-service-db:
# condition: service_healthy
ports:
- "8002:80"

Expand Down Expand Up @@ -71,7 +68,7 @@ services:
- /app/node_modules
ports:
- "8005:80"

communication-service:
container_name: communication-service
build:
Expand All @@ -83,34 +80,6 @@ services:
ports:
- "8006:80"

# user-service-db:
# container_name: user-service-db
# build:
# context: ./backend/user-service/db
# dockerfile: Dockerfile.dev
# restart: always
# environment:
# MONGO_INITDB_ROOT_USERNAME: root
# MONGO_INITDB_ROOT_PASSWORD: prisma
# MONGO_REPLICA_HOST: 127.0.0.1
# MONGO_REPLICA_PORT: 27018
# ports:
# - 27018:27018
# healthcheck:
# test:
# [
# "CMD",
# "mongo",
# "admin",
# "--port",
# "27018",
# "--eval",
# "db.adminCommand('ping')",
# ]
# interval: 5s
# timeout: 2s
# retries: 20

question-service-db:
container_name: question-service-db
image: mongo:latest
Expand Down
12 changes: 6 additions & 6 deletions frontend/app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions frontend/app/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ interface CardProps extends BoxProps {
export const Card = ({ children, ...boxProps }: CardProps) => {
return (
<Box
backgroundColor="light.500"
backgroundColor="dark.900"
borderRadius="1.5rem"
borderColor="rgba(255,255,255,0.08)"
borderColor="dark.700"
borderWidth="1px"
boxShadow="0 4px 12px rgba(0,0,0,.24)"
p="2rem"
Expand Down
15 changes: 11 additions & 4 deletions frontend/app/src/components/CustomAlert/CustomAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,25 @@ export const CustomAlert = ({
isOpen={isOpen}
leastDestructiveRef={leastDestructiveRef}
onClose={onClose}
isCentered
>
<AlertDialogOverlay>
<AlertDialogContent>
<AlertDialogHeader fontSize="lg" fontWeight="bold">
<AlertDialogHeader fontSize="lg" fontWeight="medium">
{title}
</AlertDialogHeader>
<AlertDialogBody>{description}</AlertDialogBody>
<AlertDialogFooter>
{!disableCancel && <Button onClick={onClose}>Cancel</Button>}
<CustomButton colorScheme="primary" onClick={onConfirm} ml={3}>
{confirmButtonText}
</CustomButton>
{title === "Leave Room" ? (
<Button ml={2} onClick={onConfirm} variant="outlineWarning">
{confirmButtonText}
</Button>
) : (
<CustomButton ml={2} onClick={onConfirm}>
{confirmButtonText}
</CustomButton>
)}
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialogOverlay>
Expand Down
37 changes: 24 additions & 13 deletions frontend/app/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ interface DropdownProps {
options: Option[];
placeholder?: string;
value?: any;
onChangeHandler?: ((newValue: SingleValue<{
label: string;
value: any;
}>, actionMeta: ActionMeta<{
label: string;
value: any;
}>) => void) | undefined
onChangeHandler?:
| ((
newValue: SingleValue<{
label: string;
value: any;
}>,
actionMeta: ActionMeta<{
label: string;
value: any;
}>,
) => void)
| undefined;
width?: number;
}

export const Dropdown = ({
Expand All @@ -29,11 +35,14 @@ export const Dropdown = ({
options,
placeholder,
value,
onChangeHandler
onChangeHandler,
width,
}: DropdownProps) => {
return (
<VStack align="left">
<Text textStyle="text-sm" fontWeight="bold">{title}</Text>
<VStack align="left" width={width}>
<Text fontSize="sm" fontWeight="medium">
{title}
</Text>
<Select
// @ts-expect-error Issue with chakra-react-select types (https://github.com/csandman/chakra-react-select/issues/273)
chakraStyles={singleSelectStyles(size)}
Expand All @@ -43,9 +52,11 @@ export const Dropdown = ({
value,
}))}
onChange={onChangeHandler ?? undefined}
value={options.find((option) => {
return option.value === value
}) ?? undefined}
value={
options.find(option => {
return option.value === value;
}) ?? undefined
}
/>
</VStack>
);
Expand Down
6 changes: 0 additions & 6 deletions frontend/app/src/components/Layout/AvatarMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ export const AvatarMenu = ({ user }: AvatarMenuProps) => {
size="sm"
/>
<MenuList>
<MenuItem
icon={<Icon as={BiUser} />}
onClick={() => navigate(`${ROUTE.PROFILE}/${user.id}`)}
>
Profile
</MenuItem>
<MenuItem
icon={<Icon as={BiCog} />}
onClick={() => navigate(`${ROUTE.SETTINGS}`)}
Expand Down
29 changes: 15 additions & 14 deletions frontend/app/src/components/Layout/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ type NavbarProps = {
isBorderless?: boolean;
};

const NAVBAR_TABS: { name: string; href: string }[] = [
{ name: "Home", href: ROUTE.HOME },
{ name: "Questions", href: ROUTE.QUESTIONS },
];

export const Navbar = ({ isBorderless }: NavbarProps) => {
const { data } = useAuth();

const user = data?.user;
const roomId = user?.roomId;
const { pathname } = useLocation();

const NAVBAR_TABS: { name: string; href: string }[] = [
{ name: "Home", href: ROUTE.HOME },
{ name: "Profile", href: `${ROUTE.PROFILE}/${user?.id}` },
{ name: "Questions", href: ROUTE.QUESTIONS },
];

return (
<Box
borderBottomWidth={isBorderless ? "0px" : "1px"}
Expand All @@ -48,11 +49,11 @@ export const Navbar = ({ isBorderless }: NavbarProps) => {
>
<HStack
alignItems="center"
background="light.500"
borderRadius={32}
px={3}
py={1.5}
border="1px solid rgba(255,255,255,.08)"
background="dark.800"
border="1px"
borderColor="dark.700"
borderRadius="full"
p={1}
>
{NAVBAR_TABS.map(tab => (
<Link
Expand All @@ -63,13 +64,13 @@ export const Navbar = ({ isBorderless }: NavbarProps) => {
pathname.includes(tab.href) ? "dark.100" : "dark.300"
}
backgroundColor={
pathname.includes(tab.href) ? "dark.950" : ""
pathname.includes(tab.href) ? "dark.900" : ""
}
px={4}
py={2}
borderRadius={32}
py={1.5}
borderRadius="full"
variant="nav"
fontWeight="semibold"
fontWeight="medium"
>
{tab.name}
</Link>
Expand Down
12 changes: 6 additions & 6 deletions frontend/app/src/components/Layout/SessionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ export const SessionBar = ({ roomId }: SessionBarProps) => {
m="auto"
h="fit-content"
w="fit-content"
px={4}
py={3}
borderWidth="2px"
px={5}
py={2.5}
borderWidth="1px"
borderRadius="full"
borderColor="primary.500"
background="light.700"
background="dark.900"
onClick={() => navigate(`${ROUTE.ROOM}/${roomId}`)}
cursor="pointer"
_hover={{
borderColor: "primary.300",
background: "light.500",
background: "dark.700",
}}
transition="all 0.2s"
>
<Text textStyle="text-sm" fontWeight="semibold">
<Text textStyle="text-sm" fontWeight="medium">
Session in progress
</Text>
</Box>
Expand Down
7 changes: 4 additions & 3 deletions frontend/app/src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ interface ToastProps {

export const Toast = ({ status, message, onClose }: ToastProps) => (
<HStack
bg="dark.950"
bg="dark.900"
border="1px"
borderRadius="md"
borderColor={`${status === "success" ? "green" : "red"}.900`}
color={`${status === "success" ? "green" : "red"}.600`}
color={`${status === "success" ? "green" : "red"}.500`}
justifyContent="space-between"
p={2}
shadow="xl"
>
<Icon as={status === "success" ? PiCheckCircleBold : PiXCircleBold} />
<Text color={`${status === "success" ? "green" : "red"}.600`} fontSize="sm">
<Text color="dark.100" fontSize="sm">
{message}
</Text>
<IconButton
Expand Down
Loading

0 comments on commit 3eebc06

Please sign in to comment.