diff --git a/cypress/e2e/authentication.cy.ts b/cypress/e2e/authentication.cy.ts
index ba4d5005..e4d0bb29 100644
--- a/cypress/e2e/authentication.cy.ts
+++ b/cypress/e2e/authentication.cy.ts
@@ -2,7 +2,7 @@ import authSuccessResponse1 from "../fixtures/authSuccessResponse1.json";
import authSuccessResponse2 from "../fixtures/authSuccessResponse2.json";
import authSuccessRequestHeaders from "../fixtures/authSuccessRequestHeaders.json";
-import { URLS } from "@/../../frontend/app/consts";
+import { URLS } from "../../frontend/app/consts";
describe("Authentication", () => {
describe("login", () => {
diff --git a/frontend/app/(cms)/(auth)/login/page.tsx b/frontend/app/(cms)/(auth)/login/page.tsx
index 282899a9..cac3029e 100644
--- a/frontend/app/(cms)/(auth)/login/page.tsx
+++ b/frontend/app/(cms)/(auth)/login/page.tsx
@@ -1,47 +1,46 @@
-"use client";
+"use client"
-import { useAuth } from "@/app/cms-authentication/AuthContext";
-import React, { useState } from "react";
+import { useAuth } from "@/app/cms-authentication/AuthContext"
+import React, { useState } from "react"
export default function Login() {
- const { login } = useAuth();
- const [emailInput, setEmailInput] = useState("");
- const [passwordInput, setPasswordInput] = useState("");
- const [errorMessage, setErrorMessage] = useState(null);
+ const { login } = useAuth()
+ const [emailInput, setEmailInput] = useState("")
+ const [passwordInput, setPasswordInput] = useState("")
+ const [errorMessage, setErrorMessage] = useState(null)
- return (
-
- );
+ setErrorMessage(login(emailInput, passwordInput)) // login returns undefined or error message
+ }}>
+ Login
+
+ {errorMessage && {errorMessage}
}
+
+ )
}
diff --git a/frontend/app/(cms)/layout.tsx b/frontend/app/(cms)/layout.tsx
index 6e103653..52083481 100644
--- a/frontend/app/(cms)/layout.tsx
+++ b/frontend/app/(cms)/layout.tsx
@@ -1,31 +1,31 @@
-"use client";
+"use client"
-import React from "react";
-import AuthProvider, { useAuth } from "@/app/cms-authentication/AuthContext";
+import React from "react"
+import AuthProvider, { useAuth } from "@/app/cms-authentication/AuthContext"
export default function CMSLayout({ children }: { children: React.ReactNode }) {
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ )
}
function CMSLayoutWithAuth({ children }: { children: React.ReactNode }) {
- const { currentUser, logout } = useAuth();
+ const { currentUser, logout } = useAuth()
- return (
-
- {currentUser && (
- <>
-
Logged in as Admin
-
- >
- )}
+ return (
+
+ {currentUser && (
+ <>
+
Logged in as Admin
+
+ >
+ )}
- {children}
-
- );
+ {children}
+
+ )
}
diff --git a/frontend/app/(content)/news/page.tsx b/frontend/app/(content)/news/page.tsx
index c111ed59..ed1e27b3 100644
--- a/frontend/app/(content)/news/page.tsx
+++ b/frontend/app/(content)/news/page.tsx
@@ -7,7 +7,7 @@ import ButtonLink from "@/app/components/ButtonLink"
import { getMetadata } from "@/app/util"
// 👇 so npm run build passes (don't attempt to static render this page)
-export const dynamic = "force-dynamic";
+export const dynamic = "force-dynamic"
export const metadata = getMetadata("All News")
diff --git a/frontend/app/(content)/research/page.tsx b/frontend/app/(content)/research/page.tsx
index eb236362..b730967d 100644
--- a/frontend/app/(content)/research/page.tsx
+++ b/frontend/app/(content)/research/page.tsx
@@ -6,9 +6,9 @@ import ButtonLink from "@/app/components/ButtonLink"
import { getMetadata } from "@/app/util"
// 👇 so npm run build passes (don't attempt to static render this page)
-export const dynamic = "force-dynamic";
+export const dynamic = "force-dynamic"
-export const metadata = getMetadata("All Research");
+export const metadata = getMetadata("All Research")
export default async function AllResearchPage() {
const research = new Paginator(
diff --git a/frontend/app/cms-authentication/AuthContext.tsx b/frontend/app/cms-authentication/AuthContext.tsx
index 2d7738e2..7a3d4a90 100644
--- a/frontend/app/cms-authentication/AuthContext.tsx
+++ b/frontend/app/cms-authentication/AuthContext.tsx
@@ -1,112 +1,100 @@
-import React, { useContext, useState, useEffect } from "react";
+import React, { useContext, useState, useEffect } from "react"
import {
- AuthenticationDetails,
- CognitoUser,
- CognitoUserPool,
- CognitoUserSession,
- CognitoIdToken,
-} from "amazon-cognito-identity-js";
-import { redirect } from "next/navigation";
-import { OPEN_CMS_ROUTES, ROUTES } from "@/app/consts";
+ AuthenticationDetails,
+ CognitoUser,
+ CognitoUserPool,
+ CognitoUserSession,
+ CognitoIdToken,
+} from "amazon-cognito-identity-js"
+import { redirect } from "next/navigation"
+import { OPEN_CMS_ROUTES, ROUTES } from "@/app/consts"
type AuthContextValue = {
- currentUser: null | CognitoIdToken["payload"];
- login: any;
- logout: any;
-};
+ currentUser: null | CognitoIdToken["payload"]
+ login: any
+ logout: any
+}
// where to authenticate users from
const adminUserPool = new CognitoUserPool({
- ClientId: "7dv8g7lsl2ht3uv29q9npt0a84",
- UserPoolId: "us-east-1_1GuGm8wMs",
-});
+ ClientId: "7dv8g7lsl2ht3uv29q9npt0a84",
+ UserPoolId: "us-east-1_1GuGm8wMs",
+})
const AuthContext = React.createContext({
- currentUser: null,
- login: () => {},
-} as AuthContextValue);
+ currentUser: null,
+ login: () => {},
+} as AuthContextValue)
export function useAuth() {
- return useContext(AuthContext);
+ return useContext(AuthContext)
}
export default function AuthProvider({ children }: React.PropsWithChildren) {
- const [currentUserSession, setCurrentUserSession] = useState(
- null as AuthContextValue["currentUser"]
- );
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- const currentUser = adminUserPool.getCurrentUser();
-
- if (!currentUser) return setLoading(false);
-
- currentUser.getSession(
- (error: Error | null, session: CognitoUserSession | null) => {
- error && console.log("Error in getting user session:", error);
- session && setCurrentUserSession(session.getIdToken().payload);
- setLoading(false);
- }
- );
- }, []);
-
- useEffect(() => {
- if (loading) return; // we don't know if user is logged in or not
-
- const currentRoute = window.location.pathname;
-
- if (!currentUserSession && !OPEN_CMS_ROUTES.includes(currentRoute))
- redirect(OPEN_CMS_ROUTES[0]);
-
- if (currentUserSession && OPEN_CMS_ROUTES.includes(currentRoute))
- redirect(ROUTES.REDIRECT_AFTER_LOGIN);
- }, [currentUserSession, loading]);
-
- // returns the error if there is one
- // if login successful, returns void but sets the current user
- async function login(email: string, password: string) {
- const user = new CognitoUser({
- Username: email,
- Pool: adminUserPool,
- });
-
- const authDetails = new AuthenticationDetails({
- Username: email,
- Password: password,
- });
-
- try {
- const result: CognitoUserSession = await new Promise(
- (resolve, reject) => {
- user.authenticateUser(authDetails, {
- onSuccess: resolve,
- onFailure: reject,
- });
+ const [currentUserSession, setCurrentUserSession] = useState(null as AuthContextValue["currentUser"])
+ const [loading, setLoading] = useState(true)
+
+ useEffect(() => {
+ const currentUser = adminUserPool.getCurrentUser()
+
+ if (!currentUser) return setLoading(false)
+
+ currentUser.getSession((error: Error | null, session: CognitoUserSession | null) => {
+ error && console.log("Error in getting user session:", error)
+ session && setCurrentUserSession(session.getIdToken().payload)
+ setLoading(false)
+ })
+ }, [])
+
+ useEffect(() => {
+ if (loading) return // we don't know if user is logged in or not
+
+ const currentRoute = window.location.pathname
+
+ if (!currentUserSession && !OPEN_CMS_ROUTES.includes(currentRoute)) redirect(OPEN_CMS_ROUTES[0])
+
+ if (currentUserSession && OPEN_CMS_ROUTES.includes(currentRoute)) redirect(ROUTES.REDIRECT_AFTER_LOGIN)
+ }, [currentUserSession, loading])
+
+ // returns the error if there is one
+ // if login successful, returns void but sets the current user
+ async function login(email: string, password: string) {
+ const user = new CognitoUser({
+ Username: email,
+ Pool: adminUserPool,
+ })
+
+ const authDetails = new AuthenticationDetails({
+ Username: email,
+ Password: password,
+ })
+
+ try {
+ const result: CognitoUserSession = await new Promise((resolve, reject) => {
+ user.authenticateUser(authDetails, {
+ onSuccess: resolve,
+ onFailure: reject,
+ })
+ })
+
+ setCurrentUserSession(result.getIdToken().payload)
+ } catch (error: any) {
+ console.error("Login failed:", { error })
+ return error.message
}
- );
+ }
- setCurrentUserSession(result.getIdToken().payload);
- } catch (error: any) {
- console.error("Login failed:", { error });
- return error.message;
+ function logout() {
+ adminUserPool.getCurrentUser()?.signOut()
+ setCurrentUserSession(null)
}
- }
-
- function logout() {
- adminUserPool.getCurrentUser()?.signOut();
- setCurrentUserSession(null);
- }
-
- // expose useful auth methods/values
- const authDetails = {
- currentUser: currentUserSession,
- login,
- logout,
- };
-
- return (
-
- {!loading && children}
-
- );
+
+ // expose useful auth methods/values
+ const authDetails = {
+ currentUser: currentUserSession,
+ login,
+ logout,
+ }
+
+ return {!loading && children}
}
diff --git a/frontend/app/components/ArticleForm.tsx b/frontend/app/components/ArticleForm.tsx
index b9c35ea7..dee8b4b4 100644
--- a/frontend/app/components/ArticleForm.tsx
+++ b/frontend/app/components/ArticleForm.tsx
@@ -1,10 +1,18 @@
-import ContentEditor from "@/app/components/ContentEditor";
-import { ArticleFromCMS } from "@/app/components/ArticleFromCMS";
-import { Article, ArticleType, IArticle } from "@aapc/types";
-import React, { useState } from "react";
-import { API_URI } from "@/app/consts";
+import ContentEditor from "@/app/components/ContentEditor"
+import { ArticleFromCMS } from "@/app/components/ArticleFromCMS"
+import { Article, ArticleType, IArticle } from "@aapc/types"
+import React, { useState } from "react"
+import { API_URI } from "@/app/consts"
-export default function ArticleForm ({ articleType, actionType, article }: { articleType: ArticleType, article?: IArticle, actionType: "create" | "edit" }) {
+export default function ArticleForm({
+ articleType,
+ actionType,
+ article,
+}: {
+ articleType: ArticleType
+ article?: IArticle
+ actionType: "create" | "edit"
+}) {
const [editorContent, setEditorContent] = useState(article?.content ?? "")
const [title, setTitle] = useState(article?.title ?? "")
const [subtitle, setSubtitle] = useState(article?.subtitle ?? "")
@@ -14,13 +22,13 @@ export default function ArticleForm ({ articleType, actionType, article }: { art
title: title,
subtitle: subtitle,
content: editorContent,
- media: []
+ media: [],
}
switch (actionType) {
case "create": {
- fetch(`${API_URI}/content/${articleType === ArticleType.news? 'news': 'research'}`, {
+ fetch(`${API_URI}/content/${articleType === ArticleType.news ? "news" : "research"}`, {
method: "post",
- body: JSON.stringify(a)
+ body: JSON.stringify(a),
}).then()
}
}
@@ -39,32 +47,38 @@ export default function ArticleForm ({ articleType, actionType, article }: { art
return (
<>
Title
-
Subtitle
-
Content
-
+
Article Preview
>
diff --git a/frontend/app/consts.ts b/frontend/app/consts.ts
index 02194278..39203a49 100644
--- a/frontend/app/consts.ts
+++ b/frontend/app/consts.ts
@@ -1,41 +1,39 @@
-let apiUri, uiUri;
+let apiUri, uiUri
switch (process.env.ENV) {
- case "LOCAL": {
- apiUri = "http://localhost:3000";
- uiUri = "http://localhost:3001";
- break;
- }
- case "DEV": {
- apiUri = "https://dev-api.aapc-nz.org";
- uiUri = "https://dev.aapc-nz.org";
- break;
- }
- case "PROD": {
- apiUri = "https://api.aapc-nz.org";
- uiUri = "https://aapc-nz.org";
- break;
- }
- default: {
- apiUri = "http://localhost:3000";
- uiUri = "http://localhost:3001";
- }
+ case "LOCAL": {
+ apiUri = "http://localhost:3000"
+ uiUri = "http://localhost:3001"
+ break
+ }
+ case "DEV": {
+ apiUri = "https://dev-api.aapc-nz.org"
+ uiUri = "https://dev.aapc-nz.org"
+ break
+ }
+ case "PROD": {
+ apiUri = "https://api.aapc-nz.org"
+ uiUri = "https://aapc-nz.org"
+ break
+ }
+ default: {
+ apiUri = "http://localhost:3000"
+ uiUri = "http://localhost:3001"
+ }
}
-export const API_URI = apiUri; // can add custom uri for testing here
-export const WEBSITE_NAME = "Aotearoa Airborne Pollen Collective";
+export const API_URI = apiUri // can add custom uri for testing here
+export const WEBSITE_NAME = "Aotearoa Airborne Pollen Collective"
-export const UI_URL = uiUri;
+export const UI_URL = uiUri
export const ROUTES = {
- LOGIN: "/login",
- FORGOT_PASSWORD: "/forgot-password",
+ LOGIN: "/login",
+ FORGOT_PASSWORD: "/forgot-password",
- REDIRECT_AFTER_LOGIN: "/news/publish",
-};
+ REDIRECT_AFTER_LOGIN: "/news/publish",
+}
-export const URLS = Object.fromEntries(
- Object.entries(ROUTES).map(([name, route]) => [name, UI_URL + route])
-);
+export const URLS = Object.fromEntries(Object.entries(ROUTES).map(([name, route]) => [name, UI_URL + route]))
-export const OPEN_CMS_ROUTES = [ROUTES.LOGIN, ROUTES.FORGOT_PASSWORD]; // no auth required for these ones
+export const OPEN_CMS_ROUTES = [ROUTES.LOGIN, ROUTES.FORGOT_PASSWORD] // no auth required for these ones
diff --git a/frontend/app/globals.css b/frontend/app/globals.css
index 02d6eda7..b1d06bb7 100644
--- a/frontend/app/globals.css
+++ b/frontend/app/globals.css
@@ -3,52 +3,52 @@
@tailwind utilities;
h1 {
- @apply text-4xl font-bold tracking-tight mb-8 mt-12
+ @apply text-4xl font-bold tracking-tight mb-8 mt-12;
}
a {
- @apply text-blue-700
+ @apply text-blue-700;
}
.subtitle {
- @apply italic text-2xl text-gray-400 mb-10 block
+ @apply italic text-2xl text-gray-400 mb-10 block;
}
.button {
- @apply flex items-center justify-center py-2 px-4 bg-green-600 font-medium rounded-full text-sm transition-all bg-opacity-15 text-black hover:bg-opacity-100 hover:text-white;
+ @apply flex items-center justify-center py-2 px-4 bg-green-600 font-medium rounded-full text-sm transition-all bg-opacity-15 text-black hover:bg-opacity-100 hover:text-white;
}
#editor button {
@apply h-8 w-8 rounded-md bg-green-600 bg-opacity-15
border-2 border-green-600 border-opacity-0 transition-all
text-sm font-medium tracking-tight text-black
- hover:border-opacity-100 flex items-center justify-center
+ hover:border-opacity-100 flex items-center justify-center;
}
#editor button.active {
- @apply border-opacity-100 bg-opacity-100 text-white
+ @apply border-opacity-100 bg-opacity-100 text-white;
}
#editor button:disabled {
- @apply text-gray-500 text-opacity-40 bg-gray-500 bg-opacity-15 cursor-default hover:border-opacity-0
+ @apply text-gray-500 text-opacity-40 bg-gray-500 bg-opacity-15 cursor-default hover:border-opacity-0;
}
*:focus {
- @apply outline-none
+ @apply outline-none;
}
.form-field {
- @apply border-2 border-opacity-30 border-black border-solid rounded-2xl
+ @apply border-2 border-opacity-30 border-black border-solid rounded-2xl;
}
.form-input {
- @apply resize-none h-11 text-lg w-full px-4 pb-1 pt-2 bg-gray-500 bg-opacity-5 rounded-2xl shadow-inner
+ @apply resize-none h-11 text-lg w-full px-4 pb-1 pt-2 bg-gray-500 bg-opacity-5 rounded-2xl shadow-inner;
}
.form-label {
- @apply mt-7 mb-1.5 tracking-tight font-medium text-gray-400 uppercase text-xs
+ @apply mt-7 mb-1.5 tracking-tight font-medium text-gray-400 uppercase text-xs;
}
.form-error {
- @apply text-red-500;
+ @apply text-red-500;
}
diff --git a/tsconfig.json b/tsconfig.json
index 0f0c3680..568d419d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,10 +11,7 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
- "incremental": true,
- "paths": {
- "@/*": ["./cypress/*"]
- }
+ "incremental": true
},
"include": ["./cypress/**/*.ts"],
"exclude": ["node_modules"]