├── .nvmrc ├── backend ├── .dockerignore ├── seed │ ├── .snaplet │ │ └── config.json │ ├── seed.config.ts │ └── testData.ts ├── nodemon.json ├── prisma │ └── index.ts ├── Dockerfile ├── crons │ ├── scripts │ │ ├── expireAdminNotes.ts │ │ ├── expireAdminAnnouncements.ts │ │ └── expireLoginStreak.ts │ └── index.ts ├── types │ ├── responses.ts │ └── enums.ts ├── .eslintrc.js ├── resolvers │ ├── noteResolver.ts │ ├── reportResolver.ts │ └── loginResolver.ts ├── utils │ ├── updateLoginStreak.ts │ ├── evaluateBadge.ts │ ├── getGraphQLSchema.ts │ ├── formatDateTime.ts │ ├── checkGoalReached.ts │ └── getGraphQLMiddleware.ts ├── server.ts └── package.json ├── frontend ├── .dockerignore ├── src │ ├── react-app-env.d.ts │ ├── index.css │ ├── participant │ │ ├── pages │ │ │ ├── schedule │ │ │ │ └── Main.tsx │ │ │ ├── home │ │ │ │ ├── Main.tsx │ │ │ │ └── components │ │ │ │ │ ├── BadgeRow.tsx │ │ │ │ │ ├── AnnouncementWidget.tsx │ │ │ │ │ ├── badgeWidget.tsx │ │ │ │ │ └── HomeContent.tsx │ │ │ ├── progress │ │ │ │ ├── components │ │ │ │ │ ├── BadgeRow.tsx │ │ │ │ │ ├── BadgeWidget.tsx │ │ │ │ │ ├── SetGoal.tsx │ │ │ │ │ └── EditGoal.tsx │ │ │ │ └── elements │ │ │ │ │ └── BucksGoalCard.tsx │ │ │ └── announcements │ │ │ │ └── components │ │ │ │ └── ParticipantAnnouncementCard.tsx │ │ ├── icons │ │ │ ├── announcements │ │ │ │ ├── notification.svg │ │ │ │ ├── orangepin.svg │ │ │ │ ├── greenpin.svg │ │ │ │ ├── unread.svg │ │ │ │ ├── important.svg │ │ │ │ ├── group.svg │ │ │ │ └── profile.svg │ │ │ ├── misc │ │ │ │ ├── comment │ │ │ │ └── comment.svg │ │ │ └── status │ │ │ │ ├── complete.svg │ │ │ │ ├── assigned.svg │ │ │ │ └── excused.svg │ │ └── common │ │ │ ├── ParticipantContext.tsx │ │ │ ├── Icon.tsx │ │ │ ├── WidgetContainer.tsx │ │ │ ├── GreenButton.tsx │ │ │ ├── ParticipantRoute.tsx │ │ │ ├── TaskBar.tsx │ │ │ └── PageHeader.tsx │ ├── utils │ │ ├── sendNotification.ts │ │ ├── string_helpers.ts │ │ ├── getChakraTheme.ts │ │ ├── getApolloClient.ts │ │ └── checkRole.ts │ ├── constants │ │ ├── misc.ts │ │ ├── icons.ts │ │ └── routes.ts │ ├── Loading.tsx │ ├── index.tsx │ ├── types │ │ ├── BadgeTypes.tsx │ │ ├── component.ts │ │ ├── AnnouncementTypes.tsx │ │ └── task.ts │ ├── admin │ │ ├── common │ │ │ ├── buttons │ │ │ │ ├── OrangeButton.tsx │ │ │ │ ├── GreenButton.tsx │ │ │ │ └── SimpleButton.tsx │ │ │ ├── form │ │ │ │ ├── TextInput.tsx │ │ │ │ ├── CoreInput.tsx │ │ │ │ ├── ModalContainer.tsx │ │ │ │ └── SelectionInput.tsx │ │ │ └── misc │ │ │ │ ├── Notification.tsx │ │ │ │ ├── AdminRoute.tsx │ │ │ │ ├── DataTable.tsx │ │ │ │ └── SideBar.tsx │ │ └── pages │ │ │ ├── schedule │ │ │ └── components │ │ │ │ ├── RoomNavigation.tsx │ │ │ │ ├── ScheduleTypes.tsx │ │ │ │ ├── ScheduleListView.tsx │ │ │ │ ├── useScheduleData.ts │ │ │ │ ├── CustomIcons.tsx │ │ │ │ └── MarillacBalanceModal.tsx │ │ │ ├── home │ │ │ └── Main.tsx │ │ │ ├── participants │ │ │ ├── components │ │ │ │ ├── EmptyRoomCard.tsx │ │ │ │ ├── OccupiedRoomCard.tsx │ │ │ │ ├── AddParticipantCard.tsx │ │ │ │ └── EditPastParticipantCard.tsx │ │ │ └── Main.tsx │ │ │ ├── badges │ │ │ ├── components │ │ │ │ ├── EditCustomBadgeModal.tsx │ │ │ │ ├── CreateCustomBadgeModal.tsx │ │ │ │ └── CustomBadgeTable.tsx │ │ │ └── Main.tsx │ │ │ ├── reports │ │ │ └── components │ │ │ │ ├── AddEmailModal.tsx │ │ │ │ └── EditEmailModal.tsx │ │ │ └── announcements │ │ │ └── components │ │ │ └── EditAnnouncementModal.tsx │ ├── theme │ │ ├── colors.ts │ │ ├── form.ts │ │ └── typography.ts │ └── NotFound.tsx ├── public │ ├── assets │ │ ├── logo.png │ │ ├── favicon.ico │ │ ├── goal_trophy.png │ │ └── marillac_bucks.png │ ├── badges │ │ ├── heart.svg │ │ ├── home.svg │ │ ├── four_star.svg │ │ ├── five_star.svg │ │ ├── pencil.svg │ │ ├── wings.svg │ │ ├── tool.svg │ │ ├── flower.svg │ │ ├── money.svg │ │ ├── baby.svg │ │ ├── group.svg │ │ └── gemstone.svg │ └── index.html ├── Dockerfile.dev ├── webpack.config.js ├── tsconfig.json ├── Dockerfile ├── .eslintrc.js └── package.json ├── .gitignore ├── nixpacks.toml ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── deploy.yml │ └── lint.yml ├── docker-compose.yml └── generate-eslint-breakdown.sh /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.11.0 2 | -------------------------------------------------------------------------------- /backend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /backend/seed/.snaplet/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "adapter": "prisma" 3 | } -------------------------------------------------------------------------------- /frontend/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } -------------------------------------------------------------------------------- /backend/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "ts,js,json", 3 | "exec": "ts-node -r dotenv/config server" 4 | } 5 | -------------------------------------------------------------------------------- /frontend/public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwblueprint/marillac-place/HEAD/frontend/public/assets/logo.png -------------------------------------------------------------------------------- /frontend/public/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwblueprint/marillac-place/HEAD/frontend/public/assets/favicon.ico -------------------------------------------------------------------------------- /frontend/public/assets/goal_trophy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwblueprint/marillac-place/HEAD/frontend/public/assets/goal_trophy.png -------------------------------------------------------------------------------- /frontend/public/assets/marillac_bucks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwblueprint/marillac-place/HEAD/frontend/public/assets/marillac_bucks.png -------------------------------------------------------------------------------- /backend/prisma/index.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | const prisma = new PrismaClient(); 4 | 5 | export default prisma; 6 | -------------------------------------------------------------------------------- /frontend/src/participant/pages/schedule/Main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function ParticipantsSchedulePage() { 4 | return <>schedule page; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/utils/sendNotification.ts: -------------------------------------------------------------------------------- 1 | export function sendNotification(message: string) { 2 | localStorage.setItem("notification", message); 3 | window.location.reload(); 4 | } 5 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/announcements/notification.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/.env 3 | **/build 4 | **/venv 5 | **/__pycache__ 6 | **/*.log 7 | **/firebaseServiceAccount.json 8 | **/.DS_Store 9 | .vscode 10 | **/*.cache 11 | **/*.egg-info 12 | **/prisma/migrations 13 | **/.eslintcache 14 | .idea -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18.18.2-slim 2 | WORKDIR /app 3 | COPY . ./ 4 | RUN apt-get update -y && apt-get install -y openssl 5 | RUN yarn install 6 | ARG NODE_ENV 7 | ENV NODE_ENV=$NODE_ENV 8 | EXPOSE 5000 9 | ENTRYPOINT ["yarn", "prismaInitAndRun"] 10 | -------------------------------------------------------------------------------- /frontend/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:20-slim 2 | WORKDIR /app 3 | COPY package.json yarn.lock ./ 4 | RUN yarn config set registry https://registry.npmmirror.com/ && \ 5 | yarn install --network-timeout 600000 6 | COPY . ./ 7 | EXPOSE 3000 8 | ENTRYPOINT ["yarn", "start"] -------------------------------------------------------------------------------- /frontend/src/constants/misc.ts: -------------------------------------------------------------------------------- 1 | export const ROOM_NUMBERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 2 | 3 | export const weekdays = [ 4 | "MONDAY", 5 | "TUESDAY", 6 | "WEDNESDAY", 7 | "THURSDAY", 8 | "FRIDAY", 9 | "SATURDAY", 10 | "SUNDAY", 11 | ]; 12 | -------------------------------------------------------------------------------- /frontend/src/participant/common/ParticipantContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | type ParticipantContextType = { 4 | id: number; 5 | }; 6 | 7 | export const ParticipantContext = createContext< 8 | ParticipantContextType | undefined 9 | >(undefined); 10 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/misc/comment: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/misc/comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nixpacks.toml: -------------------------------------------------------------------------------- 1 | [phases.setup] 2 | nixPkgs = ["nodejs_22", "yarn"] 3 | 4 | [phases.install] 5 | cmds = [ 6 | "cd backend && yarn install" 7 | ] 8 | 9 | [phases.build] 10 | cmds = [ 11 | "cd backend && yarn build" 12 | ] 13 | 14 | [start] 15 | cmd = "cd backend && yarn start" 16 | 17 | 18 | -------------------------------------------------------------------------------- /frontend/src/Loading.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Spinner } from "@chakra-ui/react"; 2 | import React from "react"; 3 | 4 | export default function Loading() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/utils/string_helpers.ts: -------------------------------------------------------------------------------- 1 | export function toTitleCase(str: string): string { 2 | return str 3 | .replace(/[^a-zA-Z0-9\s]/g, " ") 4 | .toLowerCase() 5 | .split(" ") 6 | .filter((word) => word.length > 0) 7 | .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) 8 | .join(" "); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/src/participant/common/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | type IconProps = { 4 | icon: string; 5 | width: string; 6 | height: string; 7 | }; 8 | 9 | const Icon = ({ icon, width, height }: IconProps) => ( 10 | icon 11 | ); 12 | 13 | export default Icon; 14 | -------------------------------------------------------------------------------- /frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement 8 | ); 9 | 10 | root.render( 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /backend/seed/seed.config.ts: -------------------------------------------------------------------------------- 1 | import { SeedPrisma } from "@snaplet/seed/adapter-prisma"; 2 | import { defineConfig } from "@snaplet/seed/config"; 3 | import { PrismaClient } from "@prisma/client"; 4 | 5 | export default defineConfig({ 6 | adapter: () => { 7 | const client = new PrismaClient(); 8 | return new SeedPrisma(client); 9 | }, 10 | select: ["!*_prisma_migrations"], 11 | }); 12 | -------------------------------------------------------------------------------- /frontend/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies, @typescript-eslint/no-var-requires */ 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | resolve: { 6 | fallback: { 7 | buffer: require.resolve("buffer/"), 8 | }, 9 | }, 10 | plugins: [ 11 | new webpack.ProvidePlugin({ 12 | Buffer: ["buffer", "Buffer"], 13 | }), 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/public/badges/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/public/badges/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/types/BadgeTypes.tsx: -------------------------------------------------------------------------------- 1 | export enum BadgeType { 2 | SYSTEM = "SYSTEM", 3 | CUSTOM = "CUSTOM", 4 | } 5 | 6 | export interface Badge { 7 | badgeId: number; 8 | badgeType: BadgeType; 9 | name: string; 10 | description: string; 11 | isActive: boolean; 12 | isConsecutive: boolean; 13 | badgeLevel: [BadgeLevel]; 14 | } 15 | 16 | export interface BadgeLevel { 17 | badgeId: number; 18 | level: number; 19 | benchmark: number; 20 | marillacBucks: number; 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/announcements/orangepin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /backend/crons/scripts/expireAdminNotes.ts: -------------------------------------------------------------------------------- 1 | import prisma from "../../prisma"; 2 | 3 | async function expireAdminNotes(): Promise { 4 | const limit = new Date(Date.now() - 48 * 60 * 60 * 1000).toLocaleDateString( 5 | "en-ca" 6 | ); 7 | try { 8 | await prisma.note.deleteMany({ 9 | where: { 10 | creation_date: { 11 | lt: limit, 12 | }, 13 | }, 14 | }); 15 | return true; 16 | } catch (err) { 17 | console.error(err); 18 | return false; 19 | } 20 | } 21 | 22 | export default expireAdminNotes; 23 | -------------------------------------------------------------------------------- /frontend/src/constants/icons.ts: -------------------------------------------------------------------------------- 1 | // Enum for badge icon options 2 | export enum Icon { 3 | FIVE_STAR = "five_star", 4 | FOUR_STAR = "four_star", 5 | GROUP = "group", 6 | HEART = "heart", 7 | HOME = "home", 8 | BABY = "baby", 9 | WINGS = "wings", 10 | FLOWER = "flower", 11 | MONEY = "money", 12 | GEMSTONE = "gemstone", 13 | DIAMOND = "diamond", 14 | PENCIL = "pencil", 15 | TOOL = "tool", 16 | } 17 | 18 | export const iconList = [ 19 | Icon.FIVE_STAR, 20 | Icon.GROUP, 21 | Icon.HEART, 22 | Icon.HOME, 23 | Icon.BABY, 24 | Icon.WINGS, 25 | ]; 26 | -------------------------------------------------------------------------------- /frontend/src/utils/getChakraTheme.ts: -------------------------------------------------------------------------------- 1 | import { extendTheme } from "@chakra-ui/react"; 2 | import colors from "../theme/colors"; 3 | import { Text, textStyles } from "../theme/typography"; 4 | import Button from "../theme/buttons"; 5 | import { Select, Input, Textarea } from "../theme/form"; 6 | 7 | export default function getChakraTheme() { 8 | const theme = extendTheme({ 9 | colors, 10 | textStyles, 11 | components: { 12 | Button, 13 | Text, 14 | Input, 15 | Select, 16 | Textarea, 17 | }, 18 | }); 19 | 20 | return theme; 21 | } 22 | -------------------------------------------------------------------------------- /backend/crons/scripts/expireAdminAnnouncements.ts: -------------------------------------------------------------------------------- 1 | import prisma from "../../prisma"; 2 | 3 | async function expireAdminAnnouncements(): Promise { 4 | const limit = new Date(Date.now() - 48 * 60 * 60 * 1000).toLocaleString( 5 | "en-ca" 6 | ); 7 | try { 8 | await prisma.announcement.deleteMany({ 9 | where: { 10 | creation_date: { 11 | lt: limit, 12 | }, 13 | }, 14 | }); 15 | return true; 16 | } catch (err) { 17 | console.error(err); 18 | return false; 19 | } 20 | } 21 | 22 | export default expireAdminAnnouncements; 23 | -------------------------------------------------------------------------------- /frontend/src/participant/common/WidgetContainer.tsx: -------------------------------------------------------------------------------- 1 | import { Flex } from "@chakra-ui/react"; 2 | import React from "react"; 3 | 4 | type WidgetContainerProps = { 5 | children: React.ReactElement; 6 | }; 7 | 8 | export default function WidgetContainer({ children }: WidgetContainerProps) { 9 | return ( 10 | 20 | {children} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/announcements/greenpin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /backend/types/responses.ts: -------------------------------------------------------------------------------- 1 | import { gql } from "apollo-server-express"; 2 | 3 | const responses = gql` 4 | type LoginResponse { 5 | token: String! 6 | } 7 | 8 | type CalendarEvent { 9 | id: Int! 10 | title: String! 11 | start: String! 12 | end: String! 13 | allDay: Boolean! 14 | task_status: Status! 15 | task_type: TaskType! 16 | marillacBucksAddition: Int! 17 | marillac_bucks_deduction: Int! 18 | comment: String 19 | } 20 | 21 | type GetAssignedTaskResponse { 22 | SPECIFIC: [CalendarEvent!]! 23 | ANYTIME: [CalendarEvent!]! 24 | ANYDAY: [CalendarEvent!]! 25 | } 26 | `; 27 | 28 | export default responses; 29 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "types": ["node"], 19 | "typeRoots": ["node_modules/@types"] 20 | }, 21 | "include": ["src"] 22 | } 23 | -------------------------------------------------------------------------------- /frontend/public/badges/four_star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-slim 2 | WORKDIR /app 3 | 4 | # Set Node.js memory limit for build 5 | ENV NODE_OPTIONS="--max-old-space-size=4096" 6 | 7 | COPY package.json yarn.lock ./ 8 | RUN yarn config set registry https://registry.npmmirror.com/ && \ 9 | yarn install --network-timeout 600000 10 | COPY . ./ 11 | 12 | # Accept build arguments and set as environment variables for build 13 | ARG REACT_APP_BACKEND_URL 14 | ARG REACT_APP_JWT_SECRET 15 | ENV REACT_APP_BACKEND_URL=$REACT_APP_BACKEND_URL 16 | ENV REACT_APP_JWT_SECRET=$REACT_APP_JWT_SECRET 17 | 18 | # Build the production bundle 19 | RUN yarn build 20 | 21 | # Serve the static files 22 | EXPOSE 3000 23 | ENTRYPOINT ["yarn", "serve"] -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Marillac Place 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /backend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | parserOptions: { 5 | ecmaVersion: 2020, 6 | project: "./tsconfig.json", 7 | sourceType: "module", 8 | createDefaultProgram: true, 9 | tsconfigRootDir: __dirname, 10 | }, 11 | extends: [ 12 | "airbnb-typescript/base", 13 | "prettier", 14 | "plugin:prettier/recommended", 15 | "plugin:@typescript-eslint/eslint-recommended", 16 | "plugin:@typescript-eslint/recommended", 17 | ], 18 | rules: { 19 | "prettier/prettier": ["error", { endOfLine: "auto" }], 20 | "class-methods-use-this": 0, 21 | "import/prefer-default-export": "off", 22 | "no-console": "off", 23 | }, 24 | ignorePatterns: ["build/*"], 25 | }; 26 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Notion Ticket 2 | 3 | [Ticket Name](URL) 4 | 5 | 6 | 7 | ## Summary 8 | ... 9 | 10 | 11 | ## Testing Details 12 | ... 13 | 14 | 15 | ## Additional Information 16 | ... 17 | 18 | ## Checklist 19 | - [ ] All of my containers are healthy and not producing any error messages 20 | - [ ] The frontend and backend ports are set to 3000 & 5000, respectively 21 | - [ ] If new packages were installed, I ran yarn install, and there is no package-lock.json file present in the codebase 22 | -------------------------------------------------------------------------------- /frontend/public/badges/five_star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/public/badges/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/types/component.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | export type ButtonProps = { 3 | text: string; 4 | action: () => void; 5 | is_active: boolean; 6 | }; 7 | 8 | export type ModalProps = { 9 | title: string; 10 | submit_text: string; 11 | submit_action: () => void; 12 | cancel_action: () => void; 13 | children: React.ReactNode; 14 | error?: string; 15 | }; 16 | 17 | export type InputProps = { 18 | label: string; 19 | current_value: any; 20 | action: any; 21 | width?: string; 22 | }; 23 | 24 | export type TableProps = { 25 | loading: boolean; 26 | edit: boolean; 27 | selected: any; 28 | error: any; 29 | columns: { header: string; width: string; sort?: JSX.Element }[]; 30 | rows: JSX.Element[][]; 31 | editModal: JSX.Element | null; 32 | }; 33 | -------------------------------------------------------------------------------- /frontend/src/constants/routes.ts: -------------------------------------------------------------------------------- 1 | export const ADMIN_LOGIN_PAGE = "/admin/login"; 2 | export const ADMIN_HOME_PAGE = "/admin"; 3 | export const ADMIN_SCHEDULE_PAGE = "/admin/schedule"; 4 | export const ADMIN_ANNOUNCEMENTS_PAGE = "/admin/announcements"; 5 | export const ADMIN_PARTICIPANTS_PAGE = "/admin/participants"; 6 | export const ADMIN_TASKS_PAGE = "/admin/task-library"; 7 | export const ADMIN_BADGES_PAGE = "/admin/badge-library"; 8 | export const ADMIN_REPORTS_PAGE = "/admin/reports"; 9 | 10 | export const PARTICIPANTS_LOGIN_PAGE = "/login"; 11 | export const PARTICIPANTS_HOME_PAGE = "/"; 12 | export const PARTICIPANTS_SCHEDULE_PAGE = "/schedule"; 13 | export const PARTICIPANTS_ANNOUNCEMENTS_PAGE = "/announcements"; 14 | export const PARTICIPANTS_TASKS_PAGE = "/tasks"; 15 | export const PARTICIPANTS_PROGRESS_PAGE = "/progress"; 16 | -------------------------------------------------------------------------------- /frontend/src/participant/icons/announcements/unread.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/types/AnnouncementTypes.tsx: -------------------------------------------------------------------------------- 1 | export interface Participant { 2 | participant_id: number; 3 | room_number: number; 4 | arrival_date: string; 5 | departure_date?: string; 6 | } 7 | 8 | export interface UserAnnouncement { 9 | read: boolean; 10 | pinned: boolean; 11 | participant_id: number; 12 | participant: Participant; 13 | } 14 | 15 | export interface AnnouncementData { 16 | announcement_id: number; 17 | priority: string; 18 | creation_date: string; 19 | message: string; 20 | user_announcements: UserAnnouncement[]; 21 | } 22 | 23 | export interface AnnouncementDisplayInfo { 24 | announcement_id: number; 25 | rooms: number[]; 26 | creation_date: Date; 27 | message: string; 28 | } 29 | 30 | export enum Priority { 31 | NORMAL = "NORMAL", 32 | HIGH = "HIGH", 33 | CRITICAL = "CRITICAL", 34 | } 35 | -------------------------------------------------------------------------------- /backend/seed/testData.ts: -------------------------------------------------------------------------------- 1 | // Test data for production testing 2 | // This is a minimal set of test accounts that can be used in production 3 | // for testing purposes without cluttering the database with full mock data 4 | 5 | export const testParticipants = [ 6 | { 7 | participant_id: 100, 8 | password: "test123", 9 | room_number: 100, 10 | arrival_date: new Date(), 11 | account_creation_date: new Date(), 12 | departure_date: null, 13 | account_removal_date: null, 14 | marillac_bucks: 50, 15 | marillac_bucks_goal: 200, 16 | }, 17 | { 18 | participant_id: 101, 19 | password: "test123", 20 | room_number: 101, 21 | arrival_date: new Date(), 22 | account_creation_date: new Date(), 23 | departure_date: null, 24 | account_removal_date: null, 25 | marillac_bucks: 75, 26 | marillac_bucks_goal: 300, 27 | }, 28 | ]; 29 | -------------------------------------------------------------------------------- /frontend/src/admin/common/buttons/OrangeButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button, Text } from "@chakra-ui/react"; 3 | import { ButtonProps } from "../../../types/component"; 4 | 5 | export default function OrangeButton({ text, action, is_active }: ButtonProps) { 6 | return ( 7 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/admin/common/buttons/GreenButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button, Text } from "@chakra-ui/react"; 3 | import { ButtonProps } from "../../../types/component"; 4 | 5 | export default function GreenButton({ text, action, is_active }: ButtonProps) { 6 | return ( 7 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/admin/common/form/TextInput.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FormControl, Text, Textarea } from "@chakra-ui/react"; 3 | import { InputProps } from "../../../types/component"; 4 | 5 | export default function TextInput({ 6 | label, 7 | current_value, 8 | action, 9 | width = "450px", 10 | }: InputProps) { 11 | return ( 12 | 13 | 14 | {label} 15 | 16 |