= {};
76 |
77 | setWorkouts([
78 | ...data.publicWorkouts.map((e) => {
79 | obj[e.id] = e;
80 | return { label: e.name, value: e.id };
81 | }),
82 | ...data.myWorkouts.map((e) => {
83 | obj[e.id] = e;
84 | return { label: e.name, value: e.id };
85 | }),
86 | ]);
87 | setWorkoutIdToDataMap(obj);
88 | }
89 | },
90 | }
91 | );
92 |
93 | const [isModalOpen, setIsModalOpen] = useState(false);
94 | const [initialWorkoutNameTypedValue, setInitialWorkoutNameTypedValue] =
95 | useState("");
96 |
97 | const setIsCreateNewWorkoutModalOpenAndPassInitValue = ({
98 | state,
99 | initialValue,
100 | }: {
101 | state: boolean;
102 | initialValue: string;
103 | }) => {
104 | setInitialWorkoutNameTypedValue(initialValue);
105 | setIsModalOpen(state);
106 | };
107 |
108 | return (
109 |
110 |
(
114 |
229 | )}
230 | />
231 |
232 | {isModalOpen ? (
233 |
241 | ) : null}
242 |
243 | );
244 | };
245 |
246 | export default SessionSchemaForm;
247 |
--------------------------------------------------------------------------------
/apps/frontend/components/Head.tsx:
--------------------------------------------------------------------------------
1 | import Head from "next/head";
2 |
3 | export const MetaHead = ({ title }: { title?: string }) => {
4 | return (
5 |
6 | {`Sigma Fit${title ? " - " + title : ""}`}
7 |
8 |
9 |
13 |
14 |
19 |
25 |
31 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/apps/frontend/components/InputField.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorMessage, Field } from "formik";
2 |
3 | export const FormInputField = ({
4 | fieldId,
5 | fieldLabel,
6 | placeholder,
7 | isInline,
8 | type = "text",
9 | }: {
10 | fieldId: string;
11 | placeholder?: string;
12 | isInline?: boolean;
13 | fieldLabel: string;
14 | type?: string;
15 | }) => (
16 |
32 | );
33 |
--------------------------------------------------------------------------------
/apps/frontend/components/LogoWithoutBeta.tsx:
--------------------------------------------------------------------------------
1 | export const LogoWithoutBeta = ({ className }: { className: string }) => (
2 |
16 | );
17 |
--------------------------------------------------------------------------------
/apps/frontend/components/MultiCreateInput.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorMessage, useFormikContext } from "formik";
2 | import { ChangeEvent, useState } from "react";
3 | import CreatableSelect from "react-select/creatable";
4 | import { toast } from "react-toastify";
5 |
6 | export const MultiCreateInput = ({
7 | fieldId,
8 | isInline = false,
9 | targetEntity,
10 | }: {
11 | targetEntity: string;
12 | fieldId: string;
13 | isInline: boolean;
14 | }) => {
15 | const { getFieldProps, setFieldValue, getFieldMeta } = useFormikContext();
16 | const formikValue = getFieldProps(fieldId).value;
17 | const [currentTextValue, setCurrentTextValue] = useState("");
18 |
19 | const valueWithLabel = ((formikValue as any[]) ?? []).map((e: any) => ({
20 | label: e,
21 | value: Math.random() * 1000,
22 | }));
23 |
24 | const handleKeyDown: any = (event: KeyboardEvent) => {
25 | if (!currentTextValue) return;
26 | switch (event.key) {
27 | case "Enter":
28 | case "Tab":
29 | event.preventDefault();
30 | setCurrentTextValue("");
31 | setFieldValue(fieldId, [...formikValue, currentTextValue]);
32 | }
33 | };
34 |
35 | return (
36 | <>
37 |
91 | >
92 | );
93 | };
94 |
--------------------------------------------------------------------------------
/apps/frontend/components/PhoneMock.tsx:
--------------------------------------------------------------------------------
1 | export const PhoneMock = ({
2 | imgUrl,
3 | phoneTypeId = "1",
4 | className = "rounded-lg w-full mt-16",
5 | }: {
6 | imgUrl: string;
7 | phoneTypeId?: string;
8 | className?: string;
9 | }) => (
10 |
11 |
12 |
13 |
16 |

17 |
18 |
19 |
20 | );
21 |
--------------------------------------------------------------------------------
/apps/frontend/components/RenderWorkoutView.tsx:
--------------------------------------------------------------------------------
1 | export const RenderWorkoutView = ({
2 | workoutName,
3 | target,
4 | }: {
5 | workoutName: string;
6 | target: any[];
7 | }) => (
8 |
9 |
10 | (
13 |
14 | {e}
15 |
16 | ))}
17 | />
18 |
19 | );
20 |
21 | export const DescriptionText = ({
22 | name,
23 | value,
24 | size = "small",
25 | type = "justify-between",
26 | }: {
27 | name: string;
28 | value: any;
29 | size?: "med" | "small";
30 | type?: "justify-between" | "gap-2" | "gap-1" | "justify-around";
31 | }) => (
32 |
33 |
39 | {name}
40 |
41 |
44 | {value}
45 |
46 |
47 | );
48 |
--------------------------------------------------------------------------------
/apps/frontend/components/RenderWorkoutsList.tsx:
--------------------------------------------------------------------------------
1 | import { DocumentIcon, PencilAltIcon, XIcon } from "@heroicons/react/solid";
2 | import { workout } from "@sigmafit/commons/dist/prismaGenTypes";
3 | import { useState } from "react";
4 | import { SigmaModal } from "./SigmaModal";
5 | import ReactMarkdown from "react-markdown";
6 |
7 | export const RenderWorkoutsList = ({
8 | workouts,
9 | handleDelete,
10 | handleEdit,
11 | }: {
12 | workouts: workout[];
13 | handleDelete?: (workout_id: string) => void;
14 | handleEdit?: (initialWorkoutValues: workout) => void;
15 | }) => {
16 | const [isNotesModalWorkoutIndex, setIsNotesModalWorkoutIndex] = useState(-1); // -1 means closed
17 |
18 | return (
19 | <>
20 | {workouts.length ? (
21 | workouts.map((workout, index: number) => {
22 | return (
23 |
27 |
28 |
29 | {/* hidden sm:block */}
30 |
31 |

35 |
36 |
37 |
38 |
39 |
Name:
40 |
41 | {workout.name.replaceAll("_", " ")}
42 |
43 |
44 |
45 |
46 |
Category:
47 |
48 | {workout.category.replaceAll("_", " ")}
49 |
50 |
51 |
52 |
53 |
54 | Target Body Part:
55 |
56 |
57 | {(workout.target_body_part ?? "NO_DATA").replaceAll(
58 | "_",
59 | " "
60 | )}
61 |
62 |
63 |
64 |
65 |
66 | Intensity:
67 |
68 |
69 | {(workout.intensity ?? "NO_DATA").replaceAll("_", " ")}
70 |
71 |
72 |
73 |
74 |
75 |
76 | {handleDelete && (
77 | // TODO: shall we disable the btn once hit for sometime?
78 |
84 | )}
85 |
86 | {handleEdit && (
87 |
93 | )}
94 |
95 |
101 |
102 |
103 | );
104 | })
105 | ) : (
106 | No workouts found
107 | )}
108 |
109 | {isNotesModalWorkoutIndex !== -1 && workouts.length && (
110 | setIsNotesModalWorkoutIndex(-1)}
113 | >
114 |
115 |
116 |
117 |
118 |

122 |
123 |
124 |
{workouts[isNotesModalWorkoutIndex].name}
125 |
126 |
127 |
128 |
129 | Notes & Instructions
130 |
131 |
132 |
133 | {workouts[isNotesModalWorkoutIndex].notes
134 | ? workouts[isNotesModalWorkoutIndex].notes
135 | : "No Data"}
136 |
137 |
138 |
139 |
140 | )}
141 | >
142 | );
143 | };
144 |
--------------------------------------------------------------------------------
/apps/frontend/components/SessionSchemaView.tsx:
--------------------------------------------------------------------------------
1 | import { useMutation } from "react-query";
2 | import { changeStateOfSessionSchema } from "../api";
3 | import { SessionSchemaFormValueType } from "./Forms/SessionSchemaForm";
4 | import { SessionSchemaDetailsResponse } from "@sigmafit/commons";
5 | import { DuplicateIcon, PencilAltIcon } from "@heroicons/react/solid";
6 | import Link from "next/link";
7 | import { DescriptionText, RenderWorkoutView } from "./RenderWorkoutView";
8 |
9 | export const SessionSchemaView = ({
10 | initialValues,
11 | handleSubmit,
12 | waitingForServerResponse,
13 | heading,
14 | sessionSchemaId,
15 | }: {
16 | initialValues: SessionSchemaDetailsResponse;
17 | handleSubmit: (payload: SessionSchemaFormValueType) => void;
18 | waitingForServerResponse: boolean;
19 | heading: string;
20 | sessionSchemaId: string;
21 | }) => {
22 | const { mutateAsync } = useMutation(
23 | "changeStateOfSessionSchema",
24 | changeStateOfSessionSchema
25 | );
26 | return (
27 |
28 |
29 |
Workout Routine
30 |
31 | {/* If public then show a btn to clone */}
32 | {initialValues.state === "PRIVATE" ? (
33 |
34 |
38 |
39 | ) : initialValues.state === "PUBLIC" ? (
40 |
41 |
45 |
46 | ) : null}
47 | {/* If pvt then show a btn to edit */}
48 |
49 | {/* If in review then show a in review btn */}
50 |
51 |
52 | {/* print schema name */}
53 |
54 |
55 |
60 |
65 |
70 |
75 |
79 | {initialValues.state}
80 |
81 | }
82 | size="med"
83 | />
84 | {initialValues.state === "PUBLIC" ? (
85 |
90 | ) : null}
91 |
92 |
93 | {initialValues.state === "PRIVATE" ? (
94 |
115 | ) : null}
116 |
117 |
118 | {/* Print all workout blocks */}
119 | {initialValues.schema_blocks.map((e, indx) => {
120 | return (
121 |
122 | {"workout_id" in e ? (
123 | // workout instance
124 |
128 | ) : (
129 | // superset schema instance
130 |
131 |
132 |
133 |
134 | {e.superset_workout_schema.map((f, index) => (
135 |
140 | ))}
141 |
142 |
143 | )}
144 |
145 | );
146 | })}
147 |
148 | );
149 | };
150 |
--------------------------------------------------------------------------------
/apps/frontend/components/SigmaModal.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export const SigmaModal: React.FC<{
4 | children: JSX.Element | JSX.Element[];
5 | isOpen: boolean;
6 | setIsOpen: (newValue: boolean) => void;
7 | }> = ({ children, isOpen, setIsOpen }) => {
8 | if (isOpen) {
9 | return (
10 | <>
11 |
12 |
13 |
{
15 | setIsOpen(false);
16 | }}
17 | className="btn btn-sm btn-circle absolute right-2 top-2"
18 | >
19 | ✕
20 |
21 | {children}
22 |
23 |
24 | >
25 | );
26 | }
27 | return null;
28 | };
29 |
--------------------------------------------------------------------------------
/apps/frontend/components/TimeSpentChart.tsx:
--------------------------------------------------------------------------------
1 | import { Insights_TimeSpent_Response } from "@sigmafit/commons";
2 | import {
3 | Chart as ChartJS,
4 | CategoryScale,
5 | LinearScale,
6 | PointElement,
7 | LineElement,
8 | Title,
9 | Tooltip,
10 | Legend,
11 | TimeScale,
12 | BarElement,
13 | TimeSeriesScale,
14 | ArcElement,
15 | RadialLinearScale,
16 | LineController,
17 | } from "chart.js";
18 | import { Chart } from "react-chartjs-2";
19 |
20 | import { useQuery } from "react-query";
21 | import { ErrorResponse, getTimeSpentInsights } from "../api";
22 | import "chartjs-adapter-date-fns";
23 |
24 | ChartJS.register(
25 | LinearScale,
26 | PointElement,
27 | LineElement,
28 | Title,
29 | Tooltip,
30 | Legend,
31 | TimeScale,
32 | LineController
33 | );
34 |
35 | // Only for duration
36 | export const TimeSpentChart = ({ height }: { height: number }) => {
37 | const { data: timeSpentData, isLoading } = useQuery<
38 | Insights_TimeSpent_Response,
39 | ErrorResponse
40 | >("getTimeSpentInsights", getTimeSpentInsights);
41 | const month = [
42 | "January",
43 | "February",
44 | "March",
45 | "April",
46 | "May",
47 | "June",
48 | "July",
49 | "August",
50 | "September",
51 | "October",
52 | "November",
53 | "December",
54 | ];
55 | return (
56 | <>
57 | {isLoading || !timeSpentData ? (
58 | Loading...
59 | ) : (
60 |
61 | {
66 | const date = new Date(e.startTime);
67 | return date;
68 | }),
69 | datasets: [
70 | {
71 | data: timeSpentData.dataPoints.map((e) => e.duration), // in minutes
72 | cubicInterpolationMode: "monotone",
73 | borderColor: "#2563eb",
74 | },
75 | ],
76 | }}
77 | options={{
78 | responsive: true,
79 | maintainAspectRatio: false,
80 | plugins: {
81 | tooltip: {
82 | callbacks: {
83 | title: function (this, tooltipItem) {
84 | return `Session Name: ${
85 | timeSpentData.dataPoints[tooltipItem[0].dataIndex]
86 | .session_name
87 | }`;
88 | },
89 | label(this, tooltipItem) {
90 | return `Session Length: ${
91 | timeSpentData.dataPoints[tooltipItem.dataIndex].duration
92 | } minutes`;
93 | },
94 | },
95 | },
96 | legend: {
97 | display: false,
98 | },
99 | },
100 |
101 | scales: {
102 | x: {
103 | type: "time",
104 | time: {
105 | unit: "day",
106 | },
107 | title: {
108 | display: false,
109 | },
110 | },
111 | y: {
112 | beginAtZero: true,
113 | },
114 | },
115 | }}
116 | />
117 |
118 | )}
119 | >
120 | );
121 | };
122 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/AnalyticsIcon.tsx:
--------------------------------------------------------------------------------
1 | export const AnalyticsIcon = ({ className }: { className: string }) => (
2 |
12 | );
13 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/CustomXIcon.tsx:
--------------------------------------------------------------------------------
1 | export const CustomXIcon = ({ className }: { className: string }) => (
2 |
12 | );
13 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/DashboardIcon.tsx:
--------------------------------------------------------------------------------
1 | export const DashboardIcon = ({ className }: { className: string }) => (
2 |
13 | );
14 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/GitHubIcon.tsx:
--------------------------------------------------------------------------------
1 | export const GitHubIcon = () => (
2 |
5 | );
6 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/GoogleIcon.tsx:
--------------------------------------------------------------------------------
1 | export const GoogleIcon = () => (
2 |
25 | );
26 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/MoveGrabber.tsx:
--------------------------------------------------------------------------------
1 | export const MoveGrabberIcon = ({ className }: { className: string }) => {
2 | return (
3 | <>
4 |
20 | >
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/SigmaFitLogoHead.tsx:
--------------------------------------------------------------------------------
1 | export function SigmaFitLogoHead() {
2 | return (
3 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/TopWorkoutRoutinesIcon.tsx:
--------------------------------------------------------------------------------
1 | export const TopWorkoutRoutinesIcon = ({
2 | className,
3 | }: {
4 | className: string;
5 | }) => (
6 |
88 | );
89 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/TwitterIcon.tsx:
--------------------------------------------------------------------------------
1 | export const TwitterIcon = () => (
2 |
8 | );
9 |
--------------------------------------------------------------------------------
/apps/frontend/components/icons/WorkoutIcon.tsx:
--------------------------------------------------------------------------------
1 | export const WorkoutIcon = ({ className }: { className: string }) => (
2 |
37 | );
38 |
--------------------------------------------------------------------------------
/apps/frontend/hooks/useScript.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | // Credits: https://usehooks.com/useScript/
4 |
5 | export function useScript(src: string) {
6 | // Keep track of script status ("idle", "loading", "ready", "error")
7 | const [status, setStatus] = useState(src ? "loading" : "idle");
8 | useEffect(
9 | () => {
10 | // Allow falsy src value if waiting on other data needed for
11 | // constructing the script URL passed to this hook.
12 | if (!src) {
13 | setStatus("idle");
14 | return;
15 | }
16 | // Fetch existing script element by src
17 | // It may have been added by another instance of this hook
18 | let script: any = document.querySelector(`script[src="${src}"]`); // TODO: remove any
19 | if (!script) {
20 | // Create script
21 | script = document.createElement("script");
22 | script.src = src;
23 | script.async = true;
24 | script.setAttribute("data-status", "loading");
25 | // Add script to document body
26 | document.body.appendChild(script);
27 | // Store status in attribute on script
28 | // This can be read by other instances of this hook
29 | const setAttributeFromEvent = (event: any) => {
30 | script.setAttribute(
31 | "data-status",
32 | event.type === "load" ? "ready" : "error"
33 | );
34 | };
35 | script.addEventListener("load", setAttributeFromEvent);
36 | script.addEventListener("error", setAttributeFromEvent);
37 | } else {
38 | // Grab existing script status from attribute and set to state.
39 | setStatus(script.getAttribute("data-status"));
40 | }
41 | // Script event handler to update status in state
42 | // Note: Even if the script already exists we still need to add
43 | // event handlers to update the state for *this* hook instance.
44 | const setStateFromEvent = (event: any) => {
45 | setStatus(event.type === "load" ? "ready" : "error");
46 | };
47 | // Add event listeners
48 | script.addEventListener("load", setStateFromEvent);
49 | script.addEventListener("error", setStateFromEvent);
50 | // Remove event listeners on cleanup
51 | return () => {
52 | if (script) {
53 | script.removeEventListener("load", setStateFromEvent);
54 | script.removeEventListener("error", setStateFromEvent);
55 | }
56 | };
57 | },
58 | [src] // Only re-run effect if script src changes
59 | );
60 | return status;
61 | }
62 |
--------------------------------------------------------------------------------
/apps/frontend/hooks/withAuthHOC.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import React, { PropsWithChildren } from "react";
3 | import { useQuery } from "react-query";
4 | import { useGetCurrentUserQuery } from "../api";
5 | import { ErrorScreen } from "../components/ErrorScreen";
6 |
7 | export const withAuthHOC = (WrappedComponent: any): React.FC => {
8 | return () => {
9 | const { isLoading, isError, error, data } = useGetCurrentUserQuery();
10 | const router = useRouter();
11 |
12 | if (isLoading) {
13 | return null;
14 | } else if (isError) {
15 | return ;
16 | } else if (data?.is_logged_in) {
17 | return ;
18 | } else {
19 | router.push("/");
20 | return null;
21 | }
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/apps/frontend/hooks/withNoAuthHOC.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import React from "react";
3 | import { useGetCurrentUserQuery } from "../api";
4 | import { ErrorScreen } from "../components/ErrorScreen";
5 | import { Navbar } from "../components/Navbar";
6 |
7 | export const witNoAuthHOC = (WrappedComponent: any): React.FC => {
8 | return () => {
9 | const { isLoading, isError, error, data } = useGetCurrentUserQuery();
10 | const router = useRouter();
11 |
12 | if (isLoading) {
13 | return null;
14 | } else if (isError) {
15 | return ;
16 | } else {
17 | if (data?.is_logged_in) {
18 | // user logged in
19 | router.push("/dash");
20 | } else {
21 | return ;
22 | }
23 | return null;
24 | }
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/apps/frontend/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/apps/frontend/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | async rewrites() {
5 | return [
6 | {
7 | source: "/api/:slug*",
8 | destination: `${process.env.SERVER_URL}/api/:slug*`, // Proxy to Backend
9 | },
10 | ];
11 | },
12 | };
13 | const withPWA = require("next-pwa");
14 |
15 | module.exports = withPWA({
16 | ...nextConfig,
17 | pwa: {
18 | dest: "./public",
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/apps/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sigmafit/frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint && tsc --noEmit",
10 | "format": "prettier --write . --ignore-path .gitignore"
11 | },
12 | "dependencies": {
13 | "@headlessui/react": "^1.6.6",
14 | "@heroicons/react": "^1.0.6",
15 | "@tailwindcss/typography": "^0.5.2",
16 | "axios": "^0.27.2",
17 | "chart.js": "^3.8.0",
18 | "chartjs-adapter-date-fns": "^2.0.0",
19 | "daisyui": "^2.17.0",
20 | "date-fns": "^2.28.0",
21 | "formik": "^2.2.9",
22 | "next": "12.2.0",
23 | "next-pwa": "5.4.0",
24 | "react": "18.2.0",
25 | "react-chartjs-2": "^4.3.1",
26 | "react-dom": "18.2.0",
27 | "react-draggable": "^4.4.5",
28 | "react-markdown": "^8.0.3",
29 | "react-query": "^3.39.1",
30 | "react-select": "^5.3.2",
31 | "react-sortablejs": "^6.1.4",
32 | "react-toastify": "^9.0.5",
33 | "sortablejs": "^1.15.0",
34 | "yup": "^0.32.11"
35 | },
36 | "devDependencies": {
37 | "@sigmafit/commons": "1.0.0",
38 | "@types/node": "18.0.0",
39 | "@types/react": "^18.0.15",
40 | "@types/react-dom": "^18.0.6",
41 | "@types/sortablejs": "^1.13.0",
42 | "autoprefixer": "^10.4.7",
43 | "eslint": "8.18.0",
44 | "eslint-config-next": "12.2.0",
45 | "postcss": "^8.4.14",
46 | "prettier": "^2.7.1",
47 | "tailwindcss": "^3.1.4",
48 | "typescript": "4.7.4"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/apps/frontend/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "../styles/globals.css";
2 | import type { AppProps } from "next/app";
3 | import { QueryClient, QueryClientProvider } from "react-query";
4 | import "react-toastify/dist/ReactToastify.css";
5 | import { ToastContainer } from "react-toastify";
6 |
7 | // Create a client
8 | const queryClient = new QueryClient();
9 |
10 | function MyApp({ Component, pageProps }: AppProps) {
11 | return (
12 | <>
13 |
14 |
15 |
16 |
17 | >
18 | );
19 | }
20 |
21 | export default MyApp;
22 |
--------------------------------------------------------------------------------
/apps/frontend/pages/auth/logout.tsx:
--------------------------------------------------------------------------------
1 | import Router from "next/router";
2 | import { useQuery, useQueryClient } from "react-query";
3 | import { toast } from "react-toastify";
4 | import { ErrorResponse, logOutUser } from "../../api";
5 |
6 | const LogOut = () => {
7 | const queryClient = useQueryClient();
8 |
9 | useQuery("logOutUser", logOutUser, {
10 | onSettled: (data, error: ErrorResponse | null) => {
11 | if (error) toast(error.message, { type: "error" });
12 | else toast(data?.message, { type: "success" });
13 |
14 | queryClient.refetchQueries("getCurrentUser");
15 |
16 | Router.push("/");
17 | },
18 | });
19 |
20 | return null;
21 | };
22 |
23 | export default LogOut;
24 |
--------------------------------------------------------------------------------
/apps/frontend/pages/auth/welcome.tsx:
--------------------------------------------------------------------------------
1 | import { MetaHead } from "../../components/Head";
2 | import { LogoWithoutBeta } from "../../components/LogoWithoutBeta";
3 | import { witNoAuthHOC } from "../../hooks/withNoAuthHOC";
4 | import { TwitterIcon } from "../../components/icons/TwitterIcon";
5 | import { GitHubIcon } from "../../components/icons/GitHubIcon";
6 | import { GoogleIcon } from "../../components/icons/GoogleIcon";
7 |
8 | const Welcome = () => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Welcome Warriors!
19 |
20 |
21 |
22 | Unleash the{" "}
23 |
24 | true power
25 | {" "}
26 | of this platform by logging in:
27 |
28 |
29 |
30 |
(window.location.href = `/api/auth/google/start`)}
32 | className="bg-white h-fit text-black hover:text-white btn rounded-md shadow-xl py-3 flex justify-center items-center gap-2"
33 | >
34 |
35 |
36 | {" "}
37 | Continue with Google
38 |
39 |
(window.location.href = `/api/auth/github/start`)}
41 | className="bg-white h-fit text-black hover:text-white btn rounded-md shadow-xl py-3 hover:fill-white flex justify-center items-center gap-2"
42 | >
43 |
44 |
45 | {" "}
46 | Continue with GitHub
47 |
48 |
(window.location.href = `/api/auth/twitter/start`)}
50 | className="bg-white h-fit text-black hover:text-white btn rounded-md shadow-xl py-3 hover:fill-white flex justify-center items-center gap-2"
51 | >
52 |
53 |
54 | {" "}
55 | Continue with Twitter
56 |
57 |
58 |
59 | By logging in you accept our Privacy Policy and Terms of Service.
60 |
61 |
62 |
63 |
64 | );
65 | };
66 |
67 | export default witNoAuthHOC(Welcome);
68 |
--------------------------------------------------------------------------------
/apps/frontend/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { NextPage } from "next";
2 | import Link from "next/link";
3 | import { useGetCurrentUserQuery } from "../api";
4 | import { MetaHead } from "../components/Head";
5 | import { Navbar } from "../components/Navbar";
6 | import { witNoAuthHOC } from "../hooks/withNoAuthHOC";
7 | import { PhoneMock } from "../components/PhoneMock";
8 | import { Footer } from "../components/Footer";
9 |
10 | const Home: NextPage = () => {
11 | const { isError, isLoading, data } = useGetCurrentUserQuery();
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | {/*
*/}
20 |
21 |
22 |
23 | Workout tracking made easy.
24 |
25 |
26 | Track your progress at gym hassle free. And use our personalized
27 | insights to improve your fitness journey.
28 |
29 | {!isLoading && data?.is_logged_in ? (
30 |
31 |
34 |
35 | ) : (
36 |
37 |
40 |
41 | )}
42 |
43 |
44 |
45 |
46 |
47 |
48 |

49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Track Everything
59 |
60 |
61 | Log all your workouts on SigmaFit. It's simpler and more rugged
62 | than any notebook out there. It will help you with the planning,
63 | execution and tracking of progress.
64 |
65 |
66 |
69 |
70 |
71 |
72 |
75 |
76 |
Wide support
77 |
78 | SigmaFit lets you log the thing you want to track. You can track
79 | distance, duration, weight, reps, and anything based on your
80 | workout requirements.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | Fully customizable
89 |
90 |
91 | In SigmaFit, it's super easy to get started with community
92 | Training Routines. If you have a custom workout plan, you can
93 | create that too. SigmaFit is super customizable, and creating a
94 | training routine is a cakewalk.
95 |
96 |
97 |
104 |
105 |
106 |
107 |
110 |
111 |
Record History
112 |
113 | Personal Records are not just any numbers. They're very special
114 | for every athlete out there. SigmaFit keeps track of it and
115 | provides extra motivation to make it even bigger!
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | Sharing is caring
124 |
125 |
126 | If you've created a training routine you're particularly proud
127 | of, you can share it with the community and friends.
128 |
129 |
130 |
131 |
134 |
135 |
136 |
137 |
138 |

139 |
140 |
141 |
142 |
143 | Available on all devices
144 |
145 |
146 | SigmaFit is a progressive web app. You can run it on any browser
147 | environment. It takes lesser resources and blazingly fast.
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | );
157 | };
158 | export default witNoAuthHOC(Home);
159 |
--------------------------------------------------------------------------------
/apps/frontend/pages/profile.tsx:
--------------------------------------------------------------------------------
1 | import { CheckIcon, XIcon } from "@heroicons/react/solid";
2 | import { user } from "@sigmafit/commons/dist/prismaGenTypes";
3 | import { useQuery } from "react-query";
4 | import { ErrorResponse, getUserProfile, useGetCurrentUserQuery } from "../api";
5 | import { Footer } from "../components/Footer";
6 | import { MetaHead } from "../components/Head";
7 | import { Navbar } from "../components/Navbar";
8 | import { withAuthHOC } from "../hooks/withAuthHOC";
9 | import { DescriptionText } from "../components/RenderWorkoutView";
10 |
11 | const Profile = () => {
12 | const { data, isLoading } = useQuery(
13 | "getUserProfile",
14 | getUserProfile
15 | ); // no need to check for loading and all
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 | {isLoading || !data ? (
24 |
Loading
25 | ) : (
26 |
27 |
28 |
Profile
29 |
30 |
31 |
32 |

33 |
34 |
35 |
36 |

37 |
38 |
39 |
40 |
41 |
42 |
48 |
49 |
55 |
56 |
62 |
63 |
69 |
70 |
75 | ) : (
76 |
77 | )
78 | }
79 | type="justify-between"
80 | size="med"
81 | />
82 |
87 | ) : (
88 |
89 | )
90 | }
91 | type="justify-between"
92 | size="med"
93 | />
94 |
99 | ) : (
100 |
101 | )
102 | }
103 | type="justify-between"
104 | size="med"
105 | />
106 |
107 |
108 | )}
109 |
110 |
111 |
112 |
113 | );
114 | };
115 |
116 | export default withAuthHOC(Profile);
117 |
--------------------------------------------------------------------------------
/apps/frontend/pages/sessionSchema/[id]/clone.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import { useMutation, useQuery } from "react-query";
3 | import { toast } from "react-toastify";
4 | import {
5 | addNewSessionSchema,
6 | ErrorResponse,
7 | getSessionSchemaDetails,
8 | } from "../../../api";
9 | import { MetaHead } from "../../../components/Head";
10 | import { Navbar } from "../../../components/Navbar";
11 | import SessionSchemaForm, {
12 | SessionSchemaFormValueType,
13 | } from "../../../components/Forms/SessionSchemaForm";
14 | import {
15 | SessionSchemaCreateRequest,
16 | SessionSchemaCreateResponse,
17 | SessionSchemaDetailsResponse,
18 | } from "@sigmafit/commons";
19 | import { withAuthHOC } from "../../../hooks/withAuthHOC";
20 | import { Footer } from "../../../components/Footer";
21 |
22 | const SessionSchemaClone = () => {
23 | const router = useRouter();
24 | const { id } = router.query;
25 |
26 | const { isLoading, data } = useQuery<
27 | SessionSchemaDetailsResponse,
28 | ErrorResponse
29 | >(
30 | ["getSessionSchemaDetails", id],
31 | () => getSessionSchemaDetails(id as string),
32 | {
33 | enabled: !!id,
34 | onSettled: (data, error) => {
35 | if (error) toast(error.message, { type: "error" });
36 | },
37 | }
38 | );
39 |
40 | const { mutate } = useMutation<
41 | SessionSchemaCreateResponse,
42 | ErrorResponse,
43 | SessionSchemaCreateRequest
44 | >("addNewSessionSchema", addNewSessionSchema, {
45 | onSettled(data, error) {
46 | if (error) {
47 | toast(error.message, { type: "error" });
48 | } else if (data) {
49 | toast("successfully cloned the workout routine");
50 | router.push("/dash");
51 | }
52 | },
53 | });
54 |
55 | const handleSubmit = (payload: SessionSchemaFormValueType) => {
56 | mutate({
57 | session_name: payload.session_name,
58 | schema_blocks: payload.schema_blocks.map((block, indx) => {
59 | if ("workout_id" in block) {
60 | return { ...block, order: indx };
61 | } else {
62 | return {
63 | ...block,
64 | superset_workout_schema: block.superset_workout_schema.map(
65 | (workout, indx) => {
66 | return { ...workout, order: indx };
67 | }
68 | ),
69 | order: indx,
70 | };
71 | }
72 | }),
73 | });
74 | };
75 |
76 | return (
77 |
78 |
79 |
80 |
81 |
82 |
83 | {isLoading || !data ? (
84 |
Loading...
85 | ) : (
86 |
92 | )}
93 |
94 |
95 |
96 |
97 | );
98 | };
99 |
100 | export default withAuthHOC(SessionSchemaClone);
101 |
--------------------------------------------------------------------------------
/apps/frontend/pages/sessionSchema/[id]/edit.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import { useQuery } from "react-query";
3 | import { toast } from "react-toastify";
4 | import { ErrorResponse, getSessionSchemaDetails } from "../../../api";
5 | import { MetaHead } from "../../../components/Head";
6 | import { Navbar } from "../../../components/Navbar";
7 | import SessionSchemaForm, {
8 | SessionSchemaFormValueType,
9 | } from "../../../components/Forms/SessionSchemaForm";
10 | import { SessionSchemaDetailsResponse } from "@sigmafit/commons";
11 | import { withAuthHOC } from "../../../hooks/withAuthHOC";
12 | import { Footer } from "../../../components/Footer";
13 |
14 | // TODO: Currently we're using it as a way to show the data; editing is not allowed for now
15 | const SessionSchemaEdit = () => {
16 | const router = useRouter();
17 | const { id } = router.query;
18 |
19 | const { isLoading, data } = useQuery<
20 | SessionSchemaDetailsResponse,
21 | ErrorResponse
22 | >(
23 | ["getSessionSchemaDetails", id],
24 | () => getSessionSchemaDetails(id as string),
25 | {
26 | enabled: !!id,
27 | onSettled: (data, error) => {
28 | if (error) toast(error.message, { type: "error" });
29 | },
30 | }
31 | );
32 |
33 | const handleSubmit = (payload: SessionSchemaFormValueType) => {
34 | toast("Editing form is currently disabled..", { type: "error" });
35 | };
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
43 |
44 | {isLoading || !data ? (
45 |
Loading...
46 | ) : (
47 |
53 | )}
54 |
55 |
56 |
57 |
58 |
59 | );
60 | };
61 |
62 | export default withAuthHOC(SessionSchemaEdit);
63 |
--------------------------------------------------------------------------------
/apps/frontend/pages/sessionSchema/[id]/view.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import { useQuery } from "react-query";
3 | import { toast } from "react-toastify";
4 | import { ErrorResponse, getSessionSchemaDetails } from "../../../api";
5 | import { MetaHead } from "../../../components/Head";
6 | import { Navbar } from "../../../components/Navbar";
7 | import { SessionSchemaFormValueType } from "../../../components/Forms/SessionSchemaForm";
8 | import { SessionSchemaDetailsResponse } from "@sigmafit/commons";
9 | import { withAuthHOC } from "../../../hooks/withAuthHOC";
10 | import { Footer } from "../../../components/Footer";
11 | import { SessionSchemaView } from "../../../components/SessionSchemaView";
12 |
13 | // TODO: Currently we're using it as a way to show the data; editing is not allowed for now
14 | const SessionSchemaEdit = () => {
15 | const router = useRouter();
16 |
17 | const { id } = router.query;
18 |
19 | const { isLoading, data } = useQuery<
20 | SessionSchemaDetailsResponse,
21 | ErrorResponse
22 | >(
23 | ["getSessionSchemaDetails", id],
24 | () => getSessionSchemaDetails(id as string),
25 | {
26 | enabled: !!id,
27 | onSettled: (_, error) => {
28 | if (error) toast(error.message, { type: "error" });
29 | },
30 | }
31 | );
32 |
33 | const handleSubmit = (payload: SessionSchemaFormValueType) => {
34 | toast("Editing form is currently disabled..", { type: "error" });
35 | };
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
43 |
44 | {isLoading || !data ? (
45 |
Loading...
46 | ) : (
47 |
54 | )}
55 |
56 |
57 |
58 |
59 | );
60 | };
61 |
62 | export default withAuthHOC(SessionSchemaEdit);
63 |
--------------------------------------------------------------------------------
/apps/frontend/pages/sessionSchema/new.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router";
2 | import { useMutation } from "react-query";
3 | import { toast } from "react-toastify";
4 | import { addNewSessionSchema, ErrorResponse } from "../../api";
5 | import { MetaHead } from "../../components/Head";
6 | import { Navbar } from "../../components/Navbar";
7 | import SessionSchemaForm, {
8 | SessionSchemaFormValueType,
9 | } from "../../components/Forms/SessionSchemaForm";
10 | import { SessionSchemaCreateRequest } from "@sigmafit/commons";
11 | import { withAuthHOC } from "../../hooks/withAuthHOC";
12 | import { Footer } from "../../components/Footer";
13 |
14 | const AddSessionSchema = () => {
15 | const {
16 | isLoading: waitingForServerResponse,
17 | mutate,
18 | error,
19 | data,
20 | } = useMutation(
21 | addNewSessionSchema
22 | );
23 | const router = useRouter();
24 |
25 | const handleSubmit = (values: SessionSchemaFormValueType) => {
26 | mutate(
27 | {
28 | session_name: values.session_name,
29 | schema_blocks: values.schema_blocks.map((block, indx) => {
30 | if ("workout_id" in block) {
31 | return { ...block, order: indx };
32 | } else {
33 | return {
34 | ...block,
35 | superset_workout_schema: block.superset_workout_schema.map(
36 | (workout, indx) => {
37 | return { ...workout, order: indx };
38 | }
39 | ),
40 | order: indx,
41 | };
42 | }
43 | }),
44 | },
45 | {
46 | onSettled(data, error, variables, context) {
47 | if (error) {
48 | toast(error.message, {
49 | type: "error",
50 | });
51 | } else {
52 | toast("Workout Routine added successfully.", {
53 | type: "success",
54 | });
55 | router.push("/dash");
56 | // TODO: refetch all sessions
57 | }
58 | },
59 | }
60 | );
61 | };
62 |
63 | return (
64 |
65 |
66 |
67 |
68 |
69 |
78 |
79 |
80 |
81 |
82 |
83 | );
84 | };
85 |
86 | export default withAuthHOC(AddSessionSchema);
87 |
--------------------------------------------------------------------------------
/apps/frontend/pages/sessionSchema/top.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ArrowLeftIcon,
3 | ArrowRightIcon,
4 | ClipboardCopyIcon,
5 | ShareIcon,
6 | ThumbUpIcon,
7 | } from "@heroicons/react/solid";
8 | import {
9 | SessionSchemaVoteRequest,
10 | SessionSchemaVoteResponse,
11 | SessionSchema_Top_Request,
12 | SessionSchema_Top_Response,
13 | } from "@sigmafit/commons";
14 | import Link from "next/link";
15 | import { useState } from "react";
16 | import { useMutation, useQuery, useQueryClient } from "react-query";
17 | import { toast } from "react-toastify";
18 | import {
19 | ErrorResponse,
20 | getTopSessionSchema,
21 | voteASessionSchema,
22 | } from "../../api";
23 | import { Footer } from "../../components/Footer";
24 | import { MetaHead } from "../../components/Head";
25 | import { Navbar } from "../../components/Navbar";
26 | import { withAuthHOC } from "../../hooks/withAuthHOC";
27 | import { DescriptionText } from "../../components/RenderWorkoutView";
28 |
29 | const TopSessionSchema = () => {
30 | const [cursorIdArr, setCursorIdArr] = useState<
31 | SessionSchema_Top_Request["cursor_id"][]
32 | >([null]);
33 | const [currentPageIndex, setCurrentPageIndex] = useState(0);
34 |
35 | const { isLoading, data } = useQuery<
36 | SessionSchema_Top_Response,
37 | ErrorResponse
38 | >(["getTopSessionSchema", cursorIdArr[currentPageIndex]], () =>
39 | getTopSessionSchema({ cursor_id: cursorIdArr[currentPageIndex] })
40 | );
41 |
42 | const client = useQueryClient();
43 | const {
44 | mutate,
45 | isLoading: waitingForServerResponseForVote,
46 | variables,
47 | } = useMutation<
48 | SessionSchemaVoteResponse,
49 | ErrorResponse,
50 | SessionSchemaVoteRequest
51 | >("voteASessionSchema", voteASessionSchema, {
52 | onSuccess: () => {
53 | client.refetchQueries("getTopSessionSchema");
54 | },
55 | });
56 |
57 | return (
58 |
59 |
60 |
61 |
62 |
63 |
Top workout routines
64 |
65 | {isLoading || !data ? (
66 |
Loading..
67 | ) : data.results.length ? (
68 |
69 | {data.results.map((e) => {
70 | const isVoted = e.session_schema_vote_by_user.length;
71 | return (
72 |
73 | {/* have a card to show top workouts */}
74 |
75 |
76 |
77 |
78 | {e.name}
79 |
80 |
81 |
85 |
89 |
93 |
97 |
101 |
102 |
103 |
122 |
{
125 | toast("Link successfully copied to clipboard", {
126 | type: "info",
127 | });
128 | const link = `${window.location.origin}/sessionSchema/${e.id}/view`;
129 | navigator.clipboard.writeText(link);
130 | }}
131 | >
132 | Share
133 |
134 |
135 |
136 | {" "}
137 | Clone
138 |
139 |
140 |
141 |
142 |
143 | );
144 | })}
145 |
146 |
147 |
158 |
169 |
170 |
171 | ) : (
172 |
No data
173 | )}
174 |
175 |
176 |
177 |
178 | );
179 | };
180 |
181 | export default withAuthHOC(TopSessionSchema);
182 |
--------------------------------------------------------------------------------
/apps/frontend/pages/workout/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | WorkoutListResponse,
3 | Workout_Delete_Response,
4 | } from "@sigmafit/commons";
5 | import { useState } from "react";
6 | import { useMutation, useQuery, useQueryClient } from "react-query";
7 | import { toast } from "react-toastify";
8 | import { deleteWorkout, ErrorResponse, getAllWorkouts } from "../../api";
9 | import {
10 | CreateNewOrEditWorkoutModal,
11 | defaultInitialValues_WorkoutForm,
12 | } from "../../components/CreateNewOrEditWorkoutModal";
13 | import { MetaHead } from "../../components/Head";
14 | import { Navbar } from "../../components/Navbar";
15 | import { withAuthHOC } from "../../hooks/withAuthHOC";
16 | import { Footer } from "../../components/Footer";
17 | import { RenderWorkoutsList } from "../../components/RenderWorkoutsList";
18 |
19 | const Workouts = () => {
20 | const { data, isLoading } = useQuery(
21 | "getAllWorkouts",
22 | getAllWorkouts,
23 | {
24 | onSettled: (data, error) => {
25 | if (error) toast(error.message, { type: "error" });
26 | },
27 | }
28 | );
29 |
30 | const [isModalOpen, setIsModalOpen] = useState(false);
31 |
32 | const queryClient = useQueryClient();
33 |
34 | const {
35 | mutate,
36 | isLoading: waitingForServerResponseForDeleteWorkout,
37 | variables,
38 | } = useMutation(
39 | "deleteWorkout",
40 | deleteWorkout,
41 | {
42 | onError(error) {
43 | toast(error.message, { type: "error" });
44 | },
45 | onSuccess(data) {
46 | const workouts =
47 | queryClient.getQueryData("getAllWorkouts");
48 | if (workouts) {
49 | queryClient.setQueriesData("getAllWorkouts", {
50 | publicWorkouts: workouts.publicWorkouts,
51 | myWorkouts: workouts.myWorkouts.filter(
52 | (e) => e.id !== data.deleted_workout_id
53 | ),
54 | });
55 | }
56 |
57 | toast(data.message, { type: "success" });
58 | },
59 | }
60 | );
61 |
62 | const [workoutInitialData, setWorkoutInitialData] = useState({
63 | initialValues: defaultInitialValues_WorkoutForm,
64 | existingWorkoutId: "",
65 | });
66 |
67 | return (
68 |
69 |
70 |
71 |
72 |
73 |
My workouts
74 |
86 |
87 | {isLoading && (
88 |
Loading workouts...
89 | )}
90 | {data ? (
91 |
{
93 | if (
94 | confirm(
95 | "Are you sure you want to delete? This action is irreversible."
96 | )
97 | ) {
98 | mutate(workout_id);
99 | }
100 | }}
101 | workouts={data.myWorkouts}
102 | handleEdit={(workout) => {
103 | setWorkoutInitialData({
104 | initialValues: {
105 | category: workout.category ?? "",
106 | intensity: workout.intensity ?? "",
107 | name: workout.name ?? "",
108 | target_body_part: workout.target_body_part ?? "",
109 | notes: workout.notes ?? "",
110 | workout_image_url: workout.workout_image_url ?? "",
111 | },
112 | existingWorkoutId: workout.id,
113 | });
114 | setIsModalOpen(true);
115 | }}
116 | />
117 | ) : null}
118 |
119 | Public Workouts
120 |
121 | {data ? : null}
122 |
123 |
124 |
130 |
131 |
132 | );
133 | };
134 |
135 | export default withAuthHOC(Workouts);
136 |
--------------------------------------------------------------------------------
/apps/frontend/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/apps/frontend/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #2d89ef
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/apps/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/apps/frontend/public/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/apps/frontend/public/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
49 |
--------------------------------------------------------------------------------
/apps/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SigmaFit",
3 | "short_name": "SigmaFit",
4 | "theme_color": "#f9f8f0",
5 | "background_color": "#f9f8f0",
6 | "display": "standalone",
7 | "scope": "/",
8 | "start_url": "/",
9 | "icons": [
10 | {
11 | "src": "/icons/android-chrome-192x192.png",
12 | "sizes": "192x192",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "/icons/android-chrome-512x512.png",
17 | "sizes": "512x512",
18 | "type": "image/png"
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/0.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/1.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/2.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/3.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/4.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/5.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/6.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/7.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/8.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/9.png
--------------------------------------------------------------------------------
/apps/frontend/public/mocks/pwa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SigmaFitness/sigmafit/4a594ab040475c07357b14c3714e5fb61373ce21/apps/frontend/public/mocks/pwa.png
--------------------------------------------------------------------------------
/apps/frontend/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | .form-container {
6 | width: 94%;
7 | @apply relative border-4 border-green-800 p-4 mx-auto max-w-lg text-left;
8 | }
9 |
10 | .form-container:before {
11 | background: #2c9382;
12 | content: "";
13 | display: block;
14 | position: absolute;
15 | margin-left: -15px;
16 | bottom: -15px;
17 | left: -4px;
18 | top: 15px;
19 | width: 15px;
20 | }
21 | .form-container:after {
22 | background: #2c9382;
23 | content: "";
24 | display: block;
25 | position: absolute;
26 | margin-left: -15px;
27 | bottom: -19px;
28 | left: -4px;
29 | right: 15px;
30 | height: 15px;
31 | }
32 |
33 | .landing-hero {
34 | min-height: 100vh;
35 | /* color: white !important; */
36 | /* background-image: url(https://unsplash.com/photos/doGGZWPdmQA/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8ODd8fG1vdGl2YXRpb24lMjBtb3VudGFpbnxlbnwwfHx8fDE2NTY4NDMxNDE&force=true&w=2400); */
37 |
38 | /* background-image: linear-gradient(180deg, rgba(10, 39, 51, 0.8), rgba(10, 39, 51, 0.8)), url('https://unsplash.com/photos/MsCgmHuirDo/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8OXx8Z3ltfGVufDB8fHx8MTY1NjgxMTYwOQ&force=true&w=1920'); */
39 | }
40 |
41 | .input-group :last-child {
42 | border-top-left-radius: inherit;
43 | border-top-right-radius: inherit;
44 | border-bottom-left-radius: inherit;
45 | border-bottom-right-radius: inherit;
46 | }
47 |
48 | .input-group :first-child {
49 | border-top-left-radius: inherit;
50 | border-top-right-radius: inherit;
51 | border-bottom-left-radius: inherit;
52 | border-bottom-right-radius: inherit;
53 | }
54 |
55 | .selectContainerWrapper {
56 | @apply font-medium text-xs;
57 | }
58 | .selectContainerWrapper .react-select__control,
59 | .selectContainerWrapper .react-select__menu,
60 | .selectContainerWrapper .react-select__menu-list {
61 | @apply bg-slate-50;
62 | }
63 |
64 | .selectContainerWrapper .react-select__control {
65 | outline: 0 !important;
66 | border-radius: 0 !important;
67 | border: 1px solid black !important;
68 | }
69 |
70 | .selectContainerWrapper:focus,
71 | .selectContainerWrapper:focus-visible {
72 | outline: 0 !important;
73 | outline-width: 0 !important;
74 | outline-style: none;
75 | }
76 |
--------------------------------------------------------------------------------
/apps/frontend/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./pages/**/*.{js,ts,jsx,tsx}",
5 | "./components/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | theme: {
8 | extend: {
9 | screens: {
10 | xs: "460px",
11 | xss: "300px",
12 | },
13 | },
14 | },
15 | plugins: [require("daisyui"), require("@tailwindcss/typography")],
16 |
17 | daisyui: {
18 | themes: [
19 | {
20 | mytheme: {
21 | primary: "#131517",
22 | "primary-content": "#fff",
23 |
24 | secondary: "#de3163",
25 | "secondary-content": "#fff",
26 |
27 | accent: "#3a86ff",
28 | "accent-content": "#fff",
29 |
30 | neutral: "#191D24",
31 | "neutral-content": "#fff",
32 | "neutral-dark": "131517",
33 |
34 | "base-100": "#f9f7ef",
35 | "base-200": "#FAC5FA",
36 | // "base-300": "#FFB7FF",
37 |
38 | info: "#3ABFF8",
39 |
40 | success: "#36D399",
41 |
42 | warning: "#FBBD23",
43 |
44 | error: "#F87272",
45 | },
46 | },
47 | ],
48 | },
49 | };
50 |
--------------------------------------------------------------------------------
/apps/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | // "paths": {
18 | // "@coreTypes/*": [
19 | // "../types/*"
20 | // ]
21 | // },
22 | },
23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
24 | "exclude": ["node_modules"]
25 | }
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "workspaces": [
4 | "apps/*"
5 | ],
6 | "nohoist": [
7 | "**/apps",
8 | "**/apps/**"
9 | ],
10 | "scripts": {
11 | "build": "yarn --cwd apps/commons build && (yarn --cwd apps/backend build & yarn --cwd apps/frontend build)",
12 | "lint": "yarn --cwd apps/commons lint && yarn --cwd apps/frontend lint && yarn --cwd apps/backend lint",
13 | "format": "yarn workspaces run format",
14 | "clean": "rm -rf apps/commons/dist/ lint && rm -rf apps/backend/dist/ lint && rm -rf apps/frontend/.next/",
15 | "dev": "(yarn workspace @sigmafit/commons watch & yarn workspace @sigmafit/backend dev & yarn workspace @sigmafit/frontend dev)"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------