diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/api/package.json b/api/package.json index 0a3cb7e5..6cd2965e 100644 --- a/api/package.json +++ b/api/package.json @@ -11,9 +11,6 @@ "start": "node dist/index.js", "dev": "nodemon index.ts", "email": "email dev", - "start-web": "cd ../web && yarn run dev", - "start-api": "yarn run dev", - "con": "concurrently \"yarn run start-api\" \"yarn run start-web\"", "db:generate": "drizzle-kit generate", "db:migrate": "node -r esbuild-register ./scripts/migrate.ts", "db:seed": "node -r esbuild-register ./scripts/seed.ts", @@ -28,7 +25,6 @@ "@types/node": "^20.11.17", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.18", - "concurrently": "^8.2.2", "drizzle-kit": "^0.22.1", "nodemon": "^3.0.3", "typescript": "^5.3.3" diff --git a/api/yarn.lock b/api/yarn.lock index 76ec0c6c..8e0a4274 100644 --- a/api/yarn.lock +++ b/api/yarn.lock @@ -10,13 +10,6 @@ lodash.assignwith "^4.2.0" typical "^7.1.1" -"@babel/runtime@^7.21.0": - version "7.24.5" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz" - integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== - dependencies: - regenerator-runtime "^0.14.0" - "@blakeembrey/deque@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@blakeembrey/deque/-/deque-1.0.5.tgz#f4fa17fc5ee18317ec01a763d355782c7b395eaf" @@ -764,21 +757,6 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concurrently@^8.2.2: - version "8.2.2" - resolved "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz" - integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg== - dependencies: - chalk "^4.1.2" - date-fns "^2.30.0" - lodash "^4.17.21" - rxjs "^7.8.1" - shell-quote "^1.8.1" - spawn-command "0.0.2" - supports-color "^8.1.1" - tree-kill "^1.2.2" - yargs "^17.7.2" - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" @@ -840,13 +818,6 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -date-fns@^2.30.0: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== - dependencies: - "@babel/runtime" "^7.21.0" - debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -1821,11 +1792,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -1836,13 +1802,6 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -rxjs@^7.8.1: - version "7.8.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== - dependencies: - tslib "^2.1.0" - safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" @@ -1923,11 +1882,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz" - integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== - side-channel@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" @@ -1987,11 +1941,6 @@ sparse-bitfield@^3.0.3: dependencies: memory-pager "^1.0.2" -spawn-command@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" - integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" @@ -2063,13 +2012,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - swr@2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz" @@ -2150,7 +2092,7 @@ ts-node@^10.9.1, ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tslib@2.4.1, tslib@^2.0.3, tslib@^2.1.0: +tslib@2.4.1, tslib@^2.0.3: version "2.4.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== @@ -2331,7 +2273,7 @@ yargs-parser@^21.1.1: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.1.1, yargs@^17.7.2: +yargs@^17.1.1: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== diff --git a/package.json b/package.json new file mode 100644 index 00000000..c2cd59ef --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "auis-portal", + "version": "1.0.0", + "repository": "https://github.com/UoaWDCC/auis-portal.git", + "license": "MIT", + "scripts": { + "setup": "yarn && cd ./web && yarn && cd ../strapi && yarn && cd ../api && yarn", + "dev": "concurrently \"cd ./database && docker compose up\" \"cd ./web && yarn dev\" \"cd ./strapi && yarn develop\" \"cd ./api && yarn dev\"", + "build": "cd ./web && yarn build && cd ../strapi && yarn build && cd ../api && yarn build" + }, + "devDependencies": { + "concurrently": "^8.2.2" + } +} diff --git a/web/__test__/TestScreen.test.tsx b/web/__test__/TestScreen.test.tsx deleted file mode 100644 index a460a230..00000000 --- a/web/__test__/TestScreen.test.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { expect, it } from "vitest"; -import { render, screen } from "@testing-library/react"; -import React from "react"; -import TestScreen from "../src/screens/Test"; -import { describe } from "node:test"; -import '@testing-library/jest-dom' - -describe("TestScreen component", () => { - it("should display the 'Test' message", () => { - render(); - const message = screen.getByText(/Test/i); - expect(message).toBeInTheDocument(); - }); -}); diff --git a/web/__test__/Footer.test.tsx b/web/__test__/components/Footer.test.tsx similarity index 87% rename from web/__test__/Footer.test.tsx rename to web/__test__/components/Footer.test.tsx index 277c9c6f..75a7b552 100644 --- a/web/__test__/Footer.test.tsx +++ b/web/__test__/components/Footer.test.tsx @@ -1,11 +1,11 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import { describe, it, expect, vi } from "vitest"; -import Footer from "../src/components/Footer"; +import Footer from "../../src/components/Footer"; import "@testing-library/jest-dom"; // Mock the Socials component -vi.mock("../src/components/Socials", () => ({ +vi.mock("../../src/components/Socials", () => ({ default: () =>
Socials Component
, })); diff --git a/web/__test__/Header.test.tsx b/web/__test__/components/Header.test.tsx similarity index 95% rename from web/__test__/Header.test.tsx rename to web/__test__/components/Header.test.tsx index f16d2923..4604ec45 100644 --- a/web/__test__/Header.test.tsx +++ b/web/__test__/components/Header.test.tsx @@ -2,7 +2,7 @@ import React from "react"; import { render, screen, fireEvent } from "@testing-library/react"; import { MemoryRouter } from "react-router-dom"; import { describe, it, expect, beforeEach } from "vitest"; -import Header from "../src/components/Header"; +import Header from "../../src/components/Header"; describe("Header component", () => { beforeEach(() => { @@ -68,7 +68,7 @@ describe("Header component", () => { it("should display navigation links properly on large screens", () => { resizeWindow(1024); // Simulate a large screen - const links = ["Events", "About Us", "Team", "Partners" , "Credits"]; + const links = ["Events", "About Us", "Team", "Partners", "Credits"]; links.forEach((link) => { expect(screen.getByText(link)).toBeInTheDocument(); }); diff --git a/web/__test__/components/Introduction.test.tsx b/web/__test__/components/Introduction.test.tsx new file mode 100644 index 00000000..e12da01f --- /dev/null +++ b/web/__test__/components/Introduction.test.tsx @@ -0,0 +1,71 @@ +import { MockedProvider } from "@apollo/client/testing"; +import { GET_INTRODUCTION } from "../../src/graphql/queries"; +import { describe, expect, it } from "vitest"; +import { render, screen } from "@testing-library/react"; +import Introductions from "../../src/components/Introductions"; +import React from "react"; +import { GraphQLError } from "graphql"; + +const mocks = [ + { + request: { + query: GET_INTRODUCTION, + }, + result: { + data: { + introductions: { + data: [ + { + id: 1, + attributes: { + Events: "Hate", + Description: "Be a Professional Hater", + Followers: "1000", + Members: "2000", + }, + }, + ], + }, + }, + }, + }, +]; + +describe("Introductions Component", () => { + it("renders loading", async () => { + render( + + + + ); + expect(screen.getByTestId("loading-spinner")).toBeInTheDocument(); + }); + + it("renders the mocked data", async () => { + render( + + + + ); + expect(await screen.findByText("Hate")).toBeInTheDocument(); + expect( + await screen.findByText("Be a Professional Hater") + ).toBeInTheDocument(); + expect(await screen.findByText("1000")).toBeInTheDocument(); + expect(await screen.findByText("2000")).toBeInTheDocument(); + }); + it("renders error", async () => { + const execMock = { + request: { + query: GET_INTRODUCTION, + }, + error: new GraphQLError("Error!"), + }; + render( + + + + ); + expect(await screen.findByText("CMS Offline")).toBeInTheDocument(); + }); +}); diff --git a/web/__test__/components/Partners.test.tsx b/web/__test__/components/Partners.test.tsx new file mode 100644 index 00000000..3e79ca33 --- /dev/null +++ b/web/__test__/components/Partners.test.tsx @@ -0,0 +1,76 @@ +import { MockedProvider } from "@apollo/client/testing"; +import { GET_PARTNERS } from "../../src/graphql/queries"; +import { describe, expect, it } from "vitest"; +import { render, screen } from "@testing-library/react"; +import Partners from "../../src/components/Partners"; +import React from "react"; +import { GraphQLError } from "graphql"; + +const mocks = [ + { + request: { + query: GET_PARTNERS, + }, + result: { + data: { + partners: { + data: [ + { + id: 1, + attributes: { + Name: "Dhruv", + Type: "Dal", + Location: "Nearest Dal Store", + Description: "Come to me for Dal", + Image: { + data: { + attributes: { + url: "/uploads/john_doe.jpg", + }, + }, + }, + }, + }, + ], + }, + }, + }, + }, +]; + +describe("Partner Component", () => { + it("renders loading", async () => { + render( + + + + ); + expect(screen.getByTestId("loading-spinner")).toBeInTheDocument(); + }); + + it("renders the mocked data", async () => { + render( + + + + ); + expect(await screen.findByText("Dhruv")).toBeInTheDocument(); + expect(await screen.findByText("Dal")).toBeInTheDocument(); + expect(await screen.findByText("Nearest Dal Store")).toBeInTheDocument(); + expect(await screen.findByText("Come to me for Dal")).toBeInTheDocument(); + }); + it("renders error", async () => { + const execMock = { + request: { + query: GET_PARTNERS, + }, + error: new GraphQLError("Error!"), + }; + render( + + + + ); + expect(await screen.findByText("CMS Offline")).toBeInTheDocument(); + }); +}); diff --git a/web/__test__/Socials.test.tsx b/web/__test__/components/Socials.test.tsx similarity index 90% rename from web/__test__/Socials.test.tsx rename to web/__test__/components/Socials.test.tsx index 132cadf0..d24e97c0 100644 --- a/web/__test__/Socials.test.tsx +++ b/web/__test__/components/Socials.test.tsx @@ -1,13 +1,13 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import { describe, it, expect } from "vitest"; -import Socials from "../src/components/Socials"; +import Socials from "../../src/components/Socials"; import { FacebookLink, InstagramLink, LinkedinLink, EmailLink, -} from "../src/data/data"; +} from "../../src/data/data"; describe("Socials component", () => { it("should render social media links", () => { diff --git a/web/__test__/components/SomePhotos.test.tsx b/web/__test__/components/SomePhotos.test.tsx new file mode 100644 index 00000000..40dc381f --- /dev/null +++ b/web/__test__/components/SomePhotos.test.tsx @@ -0,0 +1,72 @@ +import { MockedProvider } from "@apollo/client/testing"; +import { GET_SOME_PHOTOS } from "../../src/graphql/queries"; +import { describe, expect, it } from "vitest"; +import { render, screen } from "@testing-library/react"; +import SomePhotos from "../../src/components/SomePhotos"; +import React from "react"; +import { GraphQLError } from "graphql"; + +const mocks = [ + { + request: { + query: GET_SOME_PHOTOS, + }, + result: { + data: { + somePhotos: { + data: [ + { + id: 1, + attributes: { + Title: "AUIS Stein", + Year: "2024", + Image: { + data: { + attributes: { + url: "/uploads/john_doe.jpg", + }, + }, + }, + }, + }, + ], + }, + }, + }, + }, +]; + +describe("SomePhotos Component", () => { + it("renders loading", async () => { + render( + + + + ); + expect(screen.getByTestId("loading-spinner")).toBeInTheDocument(); + }); + + it("renders the mocked data", async () => { + render( + + + + ); + expect(await screen.findByText("AUIS Stein")).toBeInTheDocument(); + expect(await screen.findByText("2024")).toBeInTheDocument(); + }); + it("renders error", async () => { + const execMock = { + request: { + query: GET_SOME_PHOTOS, + }, + error: new GraphQLError("Error!"), + }; + render( + + + + ); + expect(await screen.findByText("CMS Offline")).toBeInTheDocument(); + }); +}); diff --git a/web/__test__/components/Values.test.tsx b/web/__test__/components/Values.test.tsx new file mode 100644 index 00000000..63ccefb7 --- /dev/null +++ b/web/__test__/components/Values.test.tsx @@ -0,0 +1,74 @@ +import { MockedProvider } from "@apollo/client/testing"; +import { GET_VALUES } from "../../src/graphql/queries"; +import { describe, expect, it } from "vitest"; +import { render, screen } from "@testing-library/react"; +import Values from "../../src/components/Values"; +import React from "react"; +import { GraphQLError } from "graphql"; + +const mocks = [ + { + request: { + query: GET_VALUES, + }, + result: { + data: { + values: { + data: [ + { + id: 1, + attributes: { + Title: "Hate", + Description: "Be a Professional Hater", + Image: { + data: { + attributes: { + url: "/uploads/john_doe.jpg", + }, + }, + }, + }, + }, + ], + }, + }, + }, + }, +]; + +describe("SomePhotos Component", () => { + it("renders loading", async () => { + render( + + + + ); + expect(screen.getByTestId("loading-spinner")).toBeInTheDocument(); + }); + + it("renders the mocked data", async () => { + render( + + + + ); + expect(await screen.findByText("Hate")).toBeInTheDocument(); + expect( + await screen.findByText("Be a Professional Hater") + ).toBeInTheDocument(); + }); + it("renders error", async () => { + const execMock = { + request: { + query: GET_VALUES, + }, + error: new GraphQLError("Error!"), + }; + render( + + + + ); + expect(await screen.findByText("CMS Offline")).toBeInTheDocument(); + }); +}); diff --git a/web/__test__/ExecScreen.test.tsx b/web/__test__/screens/ExecScreen.test.tsx similarity index 83% rename from web/__test__/ExecScreen.test.tsx rename to web/__test__/screens/ExecScreen.test.tsx index 0a7c3594..24378826 100644 --- a/web/__test__/ExecScreen.test.tsx +++ b/web/__test__/screens/ExecScreen.test.tsx @@ -1,8 +1,8 @@ import { MockedProvider } from "@apollo/client/testing"; -import { GET_EXECS } from "../src/graphql/queries"; +import { GET_EXECS } from "../../src/graphql/queries"; import { describe, expect, it } from "vitest"; import { render, screen } from "@testing-library/react"; -import ExecScreen from "../src/screens/ExecScreen"; +import ExecScreen from "../../src/screens/ExecScreen"; import React from "react"; import { GraphQLError } from "graphql"; @@ -18,10 +18,11 @@ const mocks = [ { id: 1, attributes: { - name: "Guryash", - bio: "A great leader", - position: "President", - image: { + Name: "Guryash", + Description: "A great leader", + Position: "President", + Role: "Goat", + Image: { data: { attributes: { url: "/uploads/john_doe.jpg", @@ -56,6 +57,7 @@ describe("Exec Screen", () => { expect(await screen.findByText("Guryash")).toBeInTheDocument(); expect(await screen.findByText("A great leader")).toBeInTheDocument(); expect(await screen.findByText("President")).toBeInTheDocument(); + expect(await screen.findByText("Goat")).toBeInTheDocument(); }); it("renders error", async () => { const execMock = { diff --git a/web/__test__/MapToExec.test.tsx b/web/__test__/utils/MapToExec.test.tsx similarity index 54% rename from web/__test__/MapToExec.test.tsx rename to web/__test__/utils/MapToExec.test.tsx index 07824798..01a29a51 100644 --- a/web/__test__/MapToExec.test.tsx +++ b/web/__test__/utils/MapToExec.test.tsx @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { mapToExec } from "../src/utils/mapToExec"; -import { Exec } from "../src/types/types"; +import { Exec } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; describe("mapToExec", () => { it("should map valid data correctly", () => { @@ -10,10 +10,11 @@ describe("mapToExec", () => { { id: 1, attributes: { - name: "Guryash", - bio: "A great leader", - position: "President", - image: { + Name: "Guryash", + Description: "A great leader", + Position: "President", + Role: "Leader", + Image: { data: { attributes: { url: "/uploads/john_doe.jpg", @@ -30,13 +31,14 @@ describe("mapToExec", () => { { id: 1, name: "Guryash", - bio: "A great leader", + description: "A great leader", position: "President", + role: "Leader", image: "/uploads/john_doe.jpg", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); }); it("should handle missing image field gracefully", () => { @@ -46,10 +48,11 @@ describe("mapToExec", () => { { id: 1, attributes: { - name: "Guryash", - bio: "A great vice president", - position: "Vice President", - image: null, + Name: "Guryash", + Description: "A great vice president", + Position: "Vice President", + Role: "Vice Leader", + Image: null, }, }, ], @@ -60,13 +63,14 @@ describe("mapToExec", () => { { id: 1, name: "Guryash", - bio: "A great vice president", + description: "A great vice president", position: "Vice President", + role: "Vice Leader", image: "", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); }); it("should handle missing name field gracefully", () => { @@ -76,10 +80,11 @@ describe("mapToExec", () => { { id: 1, attributes: { - name: null, - bio: "A great treasurer", - position: "Treasurer", - image: { + Name: null, + Description: "A great treasurer", + Position: "Treasurer", + Role: "Finance", + Image: { data: { attributes: { url: "/uploads/jane_doe.jpg", @@ -96,26 +101,28 @@ describe("mapToExec", () => { { id: 1, name: "", - bio: "A great treasurer", + description: "A great treasurer", position: "Treasurer", + role: "Finance", image: "/uploads/jane_doe.jpg", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); }); - it("should handle missing bio field gracefully", () => { + it("should handle missing description field gracefully", () => { const data = { execs: { data: [ { id: 1, attributes: { - name: "Guryash", - bio: null, - position: "Secretary", - image: { + Name: "Guryash", + Description: null, + Position: "Secretary", + Role: "Organizer", + Image: { data: { attributes: { url: "/uploads/john_smith.jpg", @@ -132,13 +139,14 @@ describe("mapToExec", () => { { id: 1, name: "Guryash", - bio: "", + description: "", position: "Secretary", + role: "Organizer", image: "/uploads/john_smith.jpg", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); }); it("should handle missing position field gracefully", () => { @@ -148,10 +156,11 @@ describe("mapToExec", () => { { id: 1, attributes: { - name: "Guryash", - bio: "A great secretary", - position: null, - image: { + Name: "Guryash", + Description: "A great secretary", + Position: null, + Role: "Organizer", + Image: { data: { attributes: { url: "/uploads/john_smith.jpg", @@ -168,13 +177,52 @@ describe("mapToExec", () => { { id: 1, name: "Guryash", - bio: "A great secretary", + description: "A great secretary", position: "", + role: "Organizer", image: "/uploads/john_smith.jpg", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); + }); + + it("should handle missing role field gracefully", () => { + const data = { + execs: { + data: [ + { + id: 1, + attributes: { + Name: "Guryash", + Description: "A great member", + Position: "Member", + Role: null, + Image: { + data: { + attributes: { + url: "/uploads/john_doe.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Exec[] = [ + { + id: 1, + name: "Guryash", + description: "A great member", + position: "Member", + role: "", + image: "/uploads/john_doe.jpg", + }, + ]; + + expect(Mapper.mapToExec(data)).toEqual(expected); }); it("should handle completely missing attributes gracefully", () => { @@ -193,12 +241,13 @@ describe("mapToExec", () => { { id: 1, name: "", - bio: "", + description: "", position: "", + role: "", image: "", }, ]; - expect(mapToExec(data)).toEqual(expected); + expect(Mapper.mapToExec(data)).toEqual(expected); }); }); diff --git a/web/__test__/utils/MapToIntroduction.test.tsx b/web/__test__/utils/MapToIntroduction.test.tsx new file mode 100644 index 00000000..afd14ecf --- /dev/null +++ b/web/__test__/utils/MapToIntroduction.test.tsx @@ -0,0 +1,205 @@ +import { describe, expect, it } from "vitest"; +import { Introduction } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; + +describe("mapToIntroduction", () => { + it("should map valid data correctly", () => { + const data = { + introductions: { + data: [ + { + id: 1, + attributes: { + Description: "Introduction description", + Events: "Upcoming events", + Members: "Current members", + Followers: "Followers count", + }, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 1, + description: "Introduction description", + events: "Upcoming events", + members: "Current members", + followers: "Followers count", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle missing fields gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 2, + attributes: null, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 2, + description: "", + events: "", + members: "", + followers: "", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle null description field gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 3, + attributes: { + Description: null, + Events: "Upcoming events", + Members: "Current members", + Followers: "Followers count", + }, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 3, + description: "", + events: "Upcoming events", + members: "Current members", + followers: "Followers count", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle null events field gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 4, + attributes: { + Description: "Introduction description", + Events: null, + Members: "Current members", + Followers: "Followers count", + }, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 4, + description: "Introduction description", + events: "", + members: "Current members", + followers: "Followers count", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle null members field gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 5, + attributes: { + Description: "Introduction description", + Events: "Upcoming events", + Members: null, + Followers: "Followers count", + }, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 5, + description: "Introduction description", + events: "Upcoming events", + members: "", + followers: "Followers count", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle null followers field gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 6, + attributes: { + Description: "Introduction description", + Events: "Upcoming events", + Members: "Current members", + Followers: null, + }, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 6, + description: "Introduction description", + events: "Upcoming events", + members: "Current members", + followers: "", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); + + it("should handle completely missing attributes gracefully", () => { + const data = { + introductions: { + data: [ + { + id: 7, + attributes: null, + }, + ], + }, + }; + + const expected: Introduction[] = [ + { + id: 7, + description: "", + events: "", + members: "", + followers: "", + }, + ]; + + expect(Mapper.mapToIntroduction(data)).toEqual(expected); + }); +}); diff --git a/web/__test__/utils/MapToPartner.test.tsx b/web/__test__/utils/MapToPartner.test.tsx new file mode 100644 index 00000000..74eec190 --- /dev/null +++ b/web/__test__/utils/MapToPartner.test.tsx @@ -0,0 +1,252 @@ +import { describe, expect, it } from "vitest"; +import { Partner } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; + +describe("mapToPartner", () => { + it("should map valid data correctly", () => { + const data = { + partners: { + data: [ + { + id: 1, + attributes: { + Type: "Business", + Name: "Partner One", + Description: "A leading business partner", + Location: "Farm", + Image: { + data: { + attributes: { + url: "/uploads/partner_one.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 1, + type: "Business", + name: "Partner One", + description: "A leading business partner", + location: "Farm", + image: "/uploads/partner_one.jpg", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle missing image field gracefully", () => { + const data = { + partners: { + data: [ + { + id: 2, + attributes: { + Type: "Technology", + Name: "Partner Two", + Description: "A technology partner", + Location: "City", + Image: null, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 2, + type: "Technology", + name: "Partner Two", + description: "A technology partner", + location: "City", + image: "", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle missing name field gracefully", () => { + const data = { + partners: { + data: [ + { + id: 3, + attributes: { + Type: "Finance", + Name: null, + Description: "A finance partner", + Location: "Town", + Image: { + data: { + attributes: { + url: "/uploads/partner_three.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 3, + type: "Finance", + name: "", + description: "A finance partner", + location: "Town", + image: "/uploads/partner_three.jpg", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle missing description field gracefully", () => { + const data = { + partners: { + data: [ + { + id: 4, + attributes: { + Type: "Healthcare", + Name: "Partner Four", + Description: null, + Location: "Village", + Image: { + data: { + attributes: { + url: "/uploads/partner_four.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 4, + type: "Healthcare", + name: "Partner Four", + description: "", + location: "Village", + image: "/uploads/partner_four.jpg", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle missing type field gracefully", () => { + const data = { + partners: { + data: [ + { + id: 5, + attributes: { + Type: null, + Name: "Partner Five", + Description: "A healthcare partner", + Location: "Island", + Image: { + data: { + attributes: { + url: "/uploads/partner_five.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 5, + type: "", + name: "Partner Five", + description: "A healthcare partner", + location: "Island", + image: "/uploads/partner_five.jpg", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle completely missing attributes gracefully", () => { + const data = { + partners: { + data: [ + { + id: 6, + attributes: null, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 6, + type: "", + name: "", + description: "", + location: "", + image: "", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); + + it("should handle missing location field gracefully", () => { + const data = { + partners: { + data: [ + { + id: 7, + attributes: { + Type: "Education", + Name: "Partner Seven", + Description: "An education partner", + Image: { + data: { + attributes: { + url: "/uploads/partner_seven.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Partner[] = [ + { + id: 7, + type: "Education", + name: "Partner Seven", + description: "An education partner", + location: "", + image: "/uploads/partner_seven.jpg", + }, + ]; + + expect(Mapper.mapToPartner(data)).toEqual(expected); + }); +}); diff --git a/web/__test__/utils/MapToSocials.test.tsx b/web/__test__/utils/MapToSocials.test.tsx new file mode 100644 index 00000000..056650a7 --- /dev/null +++ b/web/__test__/utils/MapToSocials.test.tsx @@ -0,0 +1,118 @@ +import { describe, expect, it } from "vitest"; +import { Social } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; + +describe("mapToSocials", () => { + it("should map valid data correctly", () => { + const data = { + socials: { + data: [ + { + id: 1, + attributes: { + Type: "Twitter", + Link: "https://twitter.com/example", + }, + }, + { + id: 2, + attributes: { + Type: "LinkedIn", + Link: "https://www.linkedin.com/example", + }, + }, + ], + }, + }; + + const expected: Social[] = [ + { + id: 1, + type: "Twitter", + link: "https://twitter.com/example", + }, + { + id: 2, + type: "LinkedIn", + link: "https://www.linkedin.com/example", + }, + ]; + + expect(Mapper.mapToSocials(data)).toEqual(expected); + }); + + it("should handle missing Type field gracefully", () => { + const data = { + socials: { + data: [ + { + id: 3, + attributes: { + Type: null, + Link: "https://instagram.com/example", + }, + }, + ], + }, + }; + + const expected: Social[] = [ + { + id: 3, + type: "", + link: "https://instagram.com/example", + }, + ]; + + expect(Mapper.mapToSocials(data)).toEqual(expected); + }); + + it("should handle missing Link field gracefully", () => { + const data = { + socials: { + data: [ + { + id: 4, + attributes: { + Type: "Instagram", + Link: null, + }, + }, + ], + }, + }; + + const expected: Social[] = [ + { + id: 4, + type: "Instagram", + link: "", + }, + ]; + + expect(Mapper.mapToSocials(data)).toEqual(expected); + }); + + it("should handle completely missing attributes gracefully", () => { + const data = { + socials: { + data: [ + { + id: 5, + attributes: null, + }, + ], + }, + }; + + const expected: Social[] = [ + { + id: 5, + type: "", + link: "", + }, + ]; + + expect(Mapper.mapToSocials(data)).toEqual(expected); + }); +}); diff --git a/web/__test__/utils/MapToSomePhotos.test.tsx b/web/__test__/utils/MapToSomePhotos.test.tsx new file mode 100644 index 00000000..c483088c --- /dev/null +++ b/web/__test__/utils/MapToSomePhotos.test.tsx @@ -0,0 +1,179 @@ +import { describe, expect, it } from "vitest"; +import { SomePhoto } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; + +describe("mapToSomePhotos", () => { + it("should map valid data correctly", () => { + const data = { + somePhotos: { + data: [ + { + id: 1, + attributes: { + Title: "Nature", + Year: "2023", + Image: { + data: { + attributes: { + url: "/uploads/nature.jpg", + }, + }, + }, + }, + }, + { + id: 2, + attributes: { + Title: "Cityscape", + Year: "2022", + Image: { + data: { + attributes: { + url: "/uploads/cityscape.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: SomePhoto[] = [ + { + id: 1, + title: "Nature", + year: "2023", + image: "/uploads/nature.jpg", + }, + { + id: 2, + title: "Cityscape", + year: "2022", + image: "/uploads/cityscape.jpg", + }, + ]; + + expect(Mapper.mapToSomePhotos(data)).toEqual(expected); + }); + + it("should handle missing Title field gracefully", () => { + const data = { + somePhotos: { + data: [ + { + id: 3, + attributes: { + Title: null, + Year: "2024", + Image: { + data: { + attributes: { + url: "/uploads/abstract.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: SomePhoto[] = [ + { + id: 3, + title: "", + year: "2024", + image: "/uploads/abstract.jpg", + }, + ]; + + expect(Mapper.mapToSomePhotos(data)).toEqual(expected); + }); + + it("should handle missing Year field gracefully", () => { + const data = { + somePhotos: { + data: [ + { + id: 4, + attributes: { + Title: "Portrait", + Year: null, + Image: { + data: { + attributes: { + url: "/uploads/portrait.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: SomePhoto[] = [ + { + id: 4, + title: "Portrait", + year: "", + image: "/uploads/portrait.jpg", + }, + ]; + + expect(Mapper.mapToSomePhotos(data)).toEqual(expected); + }); + + it("should handle missing Image field gracefully", () => { + const data = { + somePhotos: { + data: [ + { + id: 5, + attributes: { + Title: "Abstract", + Year: "2025", + Image: null, + }, + }, + ], + }, + }; + + const expected: SomePhoto[] = [ + { + id: 5, + title: "Abstract", + year: "2025", + image: "", + }, + ]; + + expect(Mapper.mapToSomePhotos(data)).toEqual(expected); + }); + + it("should handle completely missing attributes gracefully", () => { + const data = { + somePhotos: { + data: [ + { + id: 6, + attributes: null, + }, + ], + }, + }; + + const expected: SomePhoto[] = [ + { + id: 6, + title: "", + year: "", + image: "", + }, + ]; + + expect(Mapper.mapToSomePhotos(data)).toEqual(expected); + }); +}); diff --git a/web/__test__/utils/MapToValue.test.tsx b/web/__test__/utils/MapToValue.test.tsx new file mode 100644 index 00000000..d5455f46 --- /dev/null +++ b/web/__test__/utils/MapToValue.test.tsx @@ -0,0 +1,159 @@ +import { describe, expect, it } from "vitest"; +import { Value } from "../../src/types/types"; +import { Mapper } from "../../src/utils/Mapper"; + +describe("mapToValue", () => { + it("should map valid data correctly", () => { + const data = { + values: { + data: [ + { + id: 1, + attributes: { + Title: "Value One", + Description: "Description of Value One", + Image: { + data: { + attributes: { + url: "/uploads/value_one.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Value[] = [ + { + id: 1, + title: "Value One", + description: "Description of Value One", + image: "/uploads/value_one.jpg", + }, + ]; + + expect(Mapper.mapToValue(data)).toEqual(expected); + }); + + it("should handle missing image field gracefully", () => { + const data = { + values: { + data: [ + { + id: 2, + attributes: { + Title: "Value Two", + Description: "Description of Value Two", + Image: null, + }, + }, + ], + }, + }; + + const expected: Value[] = [ + { + id: 2, + title: "Value Two", + description: "Description of Value Two", + image: "", + }, + ]; + + expect(Mapper.mapToValue(data)).toEqual(expected); + }); + + it("should handle missing title field gracefully", () => { + const data = { + values: { + data: [ + { + id: 3, + attributes: { + Title: null, + Description: "Description of Value Three", + Image: { + data: { + attributes: { + url: "/uploads/value_three.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Value[] = [ + { + id: 3, + title: "", + description: "Description of Value Three", + image: "/uploads/value_three.jpg", + }, + ]; + + expect(Mapper.mapToValue(data)).toEqual(expected); + }); + + it("should handle missing description field gracefully", () => { + const data = { + values: { + data: [ + { + id: 4, + attributes: { + Title: "Value Four", + Description: null, + Image: { + data: { + attributes: { + url: "/uploads/value_four.jpg", + }, + }, + }, + }, + }, + ], + }, + }; + + const expected: Value[] = [ + { + id: 4, + title: "Value Four", + description: "", + image: "/uploads/value_four.jpg", + }, + ]; + + expect(Mapper.mapToValue(data)).toEqual(expected); + }); + + it("should handle completely missing attributes gracefully", () => { + const data = { + values: { + data: [ + { + id: 5, + attributes: null, + }, + ], + }, + }; + + const expected: Value[] = [ + { + id: 5, + title: "", + description: "", + image: "", + }, + ]; + + expect(Mapper.mapToValue(data)).toEqual(expected); + }); +}); diff --git a/web/src/components/Introductions.tsx b/web/src/components/Introductions.tsx new file mode 100644 index 00000000..9cfd472f --- /dev/null +++ b/web/src/components/Introductions.tsx @@ -0,0 +1,38 @@ +import { useQuery } from "@apollo/client"; +import { GET_INTRODUCTION } from "../graphql/queries"; +import LoadingSpinner from "./LoadingSpinner"; +import { Introduction } from "../types/types"; +import { Mapper } from "../utils/Mapper"; + +function Introductions() { + const { loading, data, error } = useQuery(GET_INTRODUCTION); + if (loading) return ; + if (error) return
CMS Offline
; + const introductions: Introduction[] = Mapper.mapToIntroduction(data); + + return ( +
+
+ {introductions.map((introduction) => ( +
+
+
+

+ {introduction.description} +

+

{introduction.events}

+

{introduction.followers}

+

{introduction.members}

+
+
+
+ ))} +
+
+ ); +} + +export default Introductions; diff --git a/web/src/components/Partners.tsx b/web/src/components/Partners.tsx new file mode 100644 index 00000000..5053b669 --- /dev/null +++ b/web/src/components/Partners.tsx @@ -0,0 +1,39 @@ +import { useQuery } from "@apollo/client"; +import { GET_PARTNERS } from "../graphql/queries"; +import LoadingSpinner from "./LoadingSpinner"; +import { Partner } from "../types/types"; +import { Mapper } from "../utils/Mapper"; + +function Partners() { + const { loading, data, error } = useQuery(GET_PARTNERS); + if (loading) return ; + if (error) return
CMS Offline
; + const partners: Partner[] = Mapper.mapToPartner(data); + + return ( +
+

Meet the Partners

+
+ {partners.map((partner) => ( +
+
+ partner information +
+

{partner.name}

+

{partner.location}

+

{partner.description}

+

{partner.type}

+
+
+
+ ))} +
+
+ ); +} + +export default Partners; diff --git a/web/src/components/SomePhotos.tsx b/web/src/components/SomePhotos.tsx index 7e2b6558..f98567a5 100644 --- a/web/src/components/SomePhotos.tsx +++ b/web/src/components/SomePhotos.tsx @@ -1,15 +1,41 @@ +import { useQuery } from "@apollo/client"; +import { GET_SOME_PHOTOS } from "../graphql/queries"; +import LoadingSpinner from "./LoadingSpinner"; +import { SomePhoto } from "../types/types"; +import { Mapper } from "../utils/Mapper"; + function SomePhotos() { - return ( - <> -
-

- Our Upcoming Events! -

+ const { loading, data, error } = useQuery(GET_SOME_PHOTOS); + if (loading) return ; + if (error) return
CMS Offline
; + const photos: SomePhoto[] = Mapper.mapToSomePhotos(data); + return ( +
+

+ Our Upcoming Events! +

+
+
+ {photos.map((photo) => ( +
+
+ partner information +
+

{photo.title}

+

{photo.year}

+
+
+
+ ))}
- - ); - } - - export default SomePhotos; - \ No newline at end of file +
+
+ ); +} + +export default SomePhotos; diff --git a/web/src/components/Values.tsx b/web/src/components/Values.tsx new file mode 100644 index 00000000..19b76ecf --- /dev/null +++ b/web/src/components/Values.tsx @@ -0,0 +1,36 @@ +import { useQuery } from "@apollo/client"; +import { GET_VALUES } from "../graphql/queries"; +import LoadingSpinner from "./LoadingSpinner"; +import { Value } from "../types/types"; +import { Mapper } from "../utils/Mapper"; + +function Values() { + const { loading, data, error } = useQuery(GET_VALUES); + if (loading) return ; + if (error) return
CMS Offline
; + const values: Value[] = Mapper.mapToValue(data); + + return ( +
+
+ {values.map((value) => ( +
+
+ partner information +
+

{value.title}

+

{value.description}

+
+
+
+ ))} +
+
+ ); +} + +export default Values; diff --git a/web/src/data/data.ts b/web/src/data/data.ts index 2eed2ac7..42afe2d3 100644 --- a/web/src/data/data.ts +++ b/web/src/data/data.ts @@ -1,50 +1,3 @@ -import type { Exec } from "../types/types"; - -export const execs: Exec[] = [ - { - id: 1, - image: "exec.png", - position: "President", - name: "Manas Sonar", - bio: "Consectetur adipiscing elit", - }, - { - id: 2, - image: "exec.png", - position: "Vice-President", - name: "Sanchani Brabhaharan", - bio: "Consectetur adipiscing elit...", - }, - { - id: 3, - image: "exec.png", - position: "Secretary", - name: "Diya Chottera", - bio: "Consectetur adipiscing elit...", - }, - { - id: 4, - image: "exec.png", - position: "Treasurer", - name: "Krish Kumar", - bio: "Consectetur adipiscing elit...", - }, - { - id: 5, - image: "exec.png", - position: "Secretary", - name: "Diya Chottera", - bio: "Consectetur adipiscing elit...", - }, - { - id: 6, - image: "exec.png", - position: "Treasurer", - name: "Krish Kumar", - bio: "Consectetur adipiscing elit...", - }, -]; - export const FacebookLink = "https://www.facebook.com/auis.uoa/"; export const InstagramLink = "https://www.instagram.com/au.indiansociety/?hl=en"; diff --git a/web/src/graphql/queries.ts b/web/src/graphql/queries.ts index 7fe21598..ad1c4520 100644 --- a/web/src/graphql/queries.ts +++ b/web/src/graphql/queries.ts @@ -6,10 +6,106 @@ export const GET_EXECS = gql` data { id attributes { - name - bio - position - image { + Name + Description + Position + Role + Image { + data { + attributes { + url + } + } + } + } + } + } + } +`; + +export const GET_PARTNERS = gql` + query { + partners { + data { + id + attributes { + Type + Name + Location + Description + Image { + data { + attributes { + url + } + } + } + } + } + } + } +`; + +export const GET_INTRODUCTION = gql` + query { + introductions { + data { + id + attributes { + Description + Events + Members + Followers + } + } + } + } +`; + +export const GET_SOCIALS = gql` + query { + socials { + data { + id + attributes { + Type + Link + } + } + } + } +`; + +export const GET_SOME_PHOTOS = gql` + query { + somePhotos { + data { + id + attributes { + Title + Year + Image { + data { + attributes { + url + } + } + } + } + } + } + } +`; + +export const GET_VALUES = gql` + query { + values { + data { + id + attributes { + Title + Description + Image { data { attributes { url diff --git a/web/src/main.tsx b/web/src/main.tsx index 5c6d9d5b..6307d6dd 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -20,6 +20,7 @@ import PVVScreen from "./screens/PVVScreen.tsx"; import LoginScreen from "./screens/LoginScreen.tsx"; import { ClerkProvider } from "@clerk/clerk-react"; import { graphqlClient } from "./graphql/client.ts"; +import CreditsScreen from "./screens/CreditsScreen.tsx"; //Add any routes for screens below const router = createBrowserRouter( @@ -27,6 +28,7 @@ const router = createBrowserRouter( }> } /> } /> + } /> } /> } /> } /> diff --git a/web/src/screens/ExecScreen.tsx b/web/src/screens/ExecScreen.tsx index 3b49b964..1a0bd9fc 100644 --- a/web/src/screens/ExecScreen.tsx +++ b/web/src/screens/ExecScreen.tsx @@ -1,15 +1,15 @@ import ReactMarkdown from "react-markdown"; import type { Exec } from "../types/types"; -import { mapToExec } from "../utils/mapToExec"; import { useQuery } from "@apollo/client"; import { GET_EXECS } from "../graphql/queries"; import LoadingSpinner from "../components/LoadingSpinner"; +import { Mapper } from "../utils/Mapper"; function ExecScreen() { const { loading, data, error } = useQuery(GET_EXECS); if (loading) return ; if (error) return
CMS Offline
; - const execs: Exec[] = mapToExec(data); + const execs: Exec[] = Mapper.mapToExec(data); return (
@@ -26,7 +26,8 @@ function ExecScreen() {

{exec.name}

{exec.position}

-

{exec.bio}

+

{exec.description}

+

{exec.role}

**Test**
diff --git a/web/src/screens/Test.tsx b/web/src/screens/Test.tsx index 66b520b8..00b70dd3 100644 --- a/web/src/screens/Test.tsx +++ b/web/src/screens/Test.tsx @@ -1,9 +1,17 @@ // import {SignedIn, SignedOut, SignInButton, UserButton} from "@clerk/clerk-react"; +import SomePhotos from "../components/SomePhotos"; +import Partners from "../components/Partners"; +import Values from "../components/Values"; +import Introductions from "@components/Introductions"; + function TestScreen() { return ( -
-

Test Screen

+
+ + + +
); } diff --git a/web/src/types/types.ts b/web/src/types/types.ts index 097a2fdc..1db044c1 100644 --- a/web/src/types/types.ts +++ b/web/src/types/types.ts @@ -2,10 +2,48 @@ export interface Exec { id: number; image: string; position: string; + role: string; name: string; - bio: string; + description: string; } export interface Props { execs: Exec[]; } + +export interface Partner { + id: number; + type: string; + name: string; + description: string; + image: string; + location: string; +} + +export interface Social { + id: number; + type: string; + link: string; +} + +export interface SomePhoto { + id: number; + title: string; + year: string; + image: string; +} + +export interface Value { + id: number; + title: string; + description: string; + image: string; +} + +export interface Introduction { + id: number; + description: string; + events: string; + members: string; + followers: string; +} diff --git a/web/src/utils/Mapper.ts b/web/src/utils/Mapper.ts new file mode 100644 index 00000000..5b1a82dd --- /dev/null +++ b/web/src/utils/Mapper.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { + Exec, + Partner, + Social, + SomePhoto, + Value, + Introduction, +} from "../types/types"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export class Mapper { + static mapToExec(data: any): Exec[] { + return data.execs.data.map((item: any) => { + const attributes = item.attributes || {}; + const imageUrl = attributes.Image?.data?.attributes?.url || ""; + + return { + id: item.id, + name: attributes.Name || "", + description: attributes.Description || "", + position: attributes.Position || "", + role: attributes.Role || "", + image: imageUrl, + }; + }); + } + + static mapToPartner(data: any): Partner[] { + return data.partners.data.map((item: any) => { + const attributes = item.attributes || {}; + const imageUrl = attributes.Image?.data?.attributes?.url || ""; + + return { + id: item.id, + type: attributes.Type || "", + name: attributes.Name || "", + description: attributes.Description || "", + location: attributes.Location || "", + image: imageUrl, + }; + }); + } + + static mapToSocials(data: any): Social[] { + return data.socials.data.map((item: any) => { + const attributes = item.attributes || {}; + return { + id: item.id, + type: attributes.Type || "", + link: attributes.Link || "", + }; + }); + } + + static mapToSomePhotos(data: any): SomePhoto[] { + return data.somePhotos.data.map((item: any) => { + const attributes = item.attributes || {}; + const imageUrl = attributes.Image?.data?.attributes?.url || ""; + + return { + id: item.id, + title: attributes.Title || "", + year: attributes.Year || "", + image: imageUrl, + }; + }); + } + + static mapToValue(data: any): Value[] { + return data.values.data.map((item: any) => { + const attributes = item.attributes || {}; + const imageUrl = attributes.Image?.data?.attributes?.url || ""; + + return { + id: item.id, + title: attributes.Title || "", + description: attributes.Description || "", + image: imageUrl, + }; + }); + } + + static mapToIntroduction = (data: any): Introduction[] => { + return data.introductions.data.map((item: any) => { + const attributes = item.attributes || {}; + return { + id: item.id, + description: attributes.Description || "", + events: attributes.Events || "", + members: attributes.Members || "", + followers: attributes.Followers || "", + }; + }); + }; +} diff --git a/web/src/utils/mapToExec.ts b/web/src/utils/mapToExec.ts deleted file mode 100644 index f026938d..00000000 --- a/web/src/utils/mapToExec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Exec } from "../types/types"; - -// biome-ignore lint/suspicious/noExplicitAny: Need type any for handling CMS -export const mapToExec = (data: any): Exec[] => { - // biome-ignore lint/suspicious/noExplicitAny: Need type any for handling CMS - return data.execs.data.map((item: any) => { - const attributes = item.attributes || {}; - const imageUrl = attributes.image?.data?.attributes?.url || ""; - - return { - id: item.id, - name: attributes.name || "", - bio: attributes.bio || "", - position: attributes.position || "", - image: imageUrl, - }; - }); -}; diff --git a/web/src/utils/mapToValue.ts b/web/src/utils/mapToValue.ts new file mode 100644 index 00000000..904cab62 --- /dev/null +++ b/web/src/utils/mapToValue.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { Value } from "../types/types"; + +// biome-ignore lint/suspicious/noExplicitAny: Need type any for handling CMS +export const mapToValue = (data: any): Value[] => { + // biome-ignore lint/suspicious/noExplicitAny: Need type any for handling CMS + return data.values.data.map((item: any) => { + const attributes = item.attributes || {}; + const imageUrl = attributes.Image?.data?.attributes?.url || ""; + + return { + id: item.id, + title: attributes.Title || "", + description: attributes.Description || "", + image: imageUrl, + }; + }); +}; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..c2c3d50d --- /dev/null +++ b/yarn.lock @@ -0,0 +1,202 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.21.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" + integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== + dependencies: + regenerator-runtime "^0.14.0" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concurrently@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784" + integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg== + dependencies: + chalk "^4.1.2" + date-fns "^2.30.0" + lodash "^4.17.21" + rxjs "^7.8.1" + shell-quote "^1.8.1" + spawn-command "0.0.2" + supports-color "^8.1.1" + tree-kill "^1.2.2" + yargs "^17.7.2" + +date-fns@^2.30.0: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +spawn-command@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +tslib@^2.1.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1"