diff --git a/internal/app/server/middleware_v2.go b/internal/app/server/middleware_v2.go index 4d4ade4..c661adb 100644 --- a/internal/app/server/middleware_v2.go +++ b/internal/app/server/middleware_v2.go @@ -19,7 +19,6 @@ import ( func JwtAuthMiddlewareV2(jwtSecretKey []byte) gin.HandlerFunc { return func(ctx *gin.Context) { tokenString, err := ctx.Cookie("jwt_token") - fmt.Println(tokenString) if err != nil { ctx.JSON(http.StatusUnauthorized, gin.H{ "status": http.StatusUnauthorized, diff --git a/internal/app/server/server.go b/internal/app/server/server.go index ee90cd5..bf96b00 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -209,6 +209,7 @@ func (s *Server) Setup() *Server { router_api_v2.GET("/user", JwtAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetAuthenticatedUserHandlerV2) router_api_v2.GET("/user/recipes", JwtAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetAuthenicatedUserRecipesV2) router_api_v2.GET("/user/favorites", JwtAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetAuthenicatedUserFavoritesV2) + router_api_v2.GET("/user/engagement", JwtAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetAuthenicatedUserEngagementV2) router_api_v2.GET("/protected", JwtAuthMiddlewareV2([]byte(cfg.JwtSecret)), func(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"msg": "YAY"}) diff --git a/internal/app/server/user_handler_v2.go b/internal/app/server/user_handler_v2.go index 048dc6a..4143ee1 100644 --- a/internal/app/server/user_handler_v2.go +++ b/internal/app/server/user_handler_v2.go @@ -75,3 +75,29 @@ func (s *Server) GetAuthenicatedUserFavoritesV2(ctx *gin.Context) { "favorites": favorites, }) } + +func (s *Server) GetAuthenicatedUserEngagementV2(ctx *gin.Context) { + user := s.deps.UserService.GetAuthenicatedUser(ctx) + if user == nil { + ctx.JSON(http.StatusUnauthorized, gin.H{ + "status": http.StatusUnauthorized, + "message": "[UNAUTHORIZED] Could not fetch authenticated user.", + }) + return + } + + engagement, err := s.deps.EngagementService.GetUserEngagement(user.Id, 6) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{ + "status": http.StatusBadRequest, + "message": fmt.Sprintf("[FAILED] Failed to get authenticated user engagement. %s", err.Error()), + }) + return + } + + ctx.JSON(http.StatusOK, gin.H{ + "status": http.StatusOK, + "message": "[OK] Successfully retrieved authenticated user engagement.", + "engagement": engagement, + }) +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..b51a1fa --- /dev/null +++ b/shell.nix @@ -0,0 +1,34 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = with pkgs; [ + go + gopls + go-tools + htmx-lsp2 + templ + tailwindcss_4 + tailwindcss-language-server + watchman + docker-language-server + dockerfile-language-server-nodejs + gcc_multi + glibc_multi + nodejs + ]; + + shellHook = '' + alias vim="nvim" + alias vi="nvim" + alias v="nvim" + + # Modify this + export PS1="\[\e[35m\]\w \$ \[\e[0m\]" + + echo "" + echo "The default environment is ready!" + echo "" + + exec zsh + ''; +} diff --git a/web/src/components/results/ActivityListItem.tsx b/web/src/components/results/ActivityListItem.tsx index de262ba..813edc8 100644 --- a/web/src/components/results/ActivityListItem.tsx +++ b/web/src/components/results/ActivityListItem.tsx @@ -5,6 +5,14 @@ interface ActivityListItemProps { engagement: Engagement; } +function FormatDate(date: Date): string { + return new Intl.DateTimeFormat("en-US", { + year: "numeric", + month: "2-digit", + day: "2-digit" + }).format(date); +} + export default function ActivityListItem({ engagement }: ActivityListItemProps) { return <>
  • @@ -12,7 +20,7 @@ export default function ActivityListItem({ engagement }: ActivityListItemProps) {engagement.Message}

    - {engagement.Created.toLocaleDateString()} + {FormatDate(new Date(engagement.Created))}

  • ; diff --git a/web/src/pages/Profile.tsx b/web/src/pages/Profile.tsx index e47d5e3..e88652b 100644 --- a/web/src/pages/Profile.tsx +++ b/web/src/pages/Profile.tsx @@ -5,7 +5,7 @@ import RecipeListItem from "../components/results/RecipeListItem"; import type { Engagement } from "../types/engagement"; import ActivityListItem from "../components/results/ActivityListItem"; import { AuthContext } from "../context/AuthContext"; -import { GetAuthenticatedUser, GetAuthenticatedUserFavorites, GetAuthenticatedUserRecipes } from "../services/UserService"; +import { GetAuthenticatedUser, GetAuthenticatedUserEngagement, GetAuthenticatedUserFavorites, GetAuthenticatedUserRecipes } from "../services/UserService"; import { isApiError, type ApiError } from "../types/api/error"; import { Logout } from "../services/AuthService"; import { useNavigate } from "react-router-dom"; @@ -23,26 +23,16 @@ export default function Profile() { const [activity, setActivity] = useState([]); const [jwt, setJwt] = useState(""); - // BUG: Remove this, used for testing - useEffect(() => { - const eng: Engagement = { - Id: 1, - Type: "made", - Message: "Created some shit", - Entity: 1, - UserId: 1, - Created: new Date(), - }; - - setActivity([eng]); - }, []); - // Log the user out and direct to the home page const logoutHandler = (): void => { void Logout(); void navigate("/v2/web/home"); } + const seeAllRecipesHandler = (): void => void navigate("/v2/web/404"); + const seeAllFavoritesHandler = (): void => void navigate("/v2/web/favorites"); + const seeAllEngagementHandler = (): void => void navigate("/v2/web/404"); + const fetchProfileData = async (): Promise => { const result_user: User | ApiError = await GetAuthenticatedUser(); if (isApiError(result_user)) { @@ -64,6 +54,13 @@ export default function Profile() { } else { setFavorites(result_favorites); } + + const result_engagement: Engagement[] | ApiError = await GetAuthenticatedUserEngagement(); + if (isApiError(result_engagement)) { + setError(result_engagement.message); + } else { + setActivity(result_engagement); + } } // Get the JWT from the cookies @@ -83,6 +80,13 @@ export default function Profile() { console.log("@error", error); }, [error]); + useEffect(() => { + if (activity) + console.log("@activity", activity); + }, [activity]); + + + return ( <> {/* User Details Section */} @@ -121,11 +125,11 @@ export default function Profile() { ) : ( recipes.slice(0, 4).map(recipe => ) )} - + @@ -138,11 +142,11 @@ export default function Profile() { ) : ( favorites.slice(0, 4).map(recipe => ) )} - + @@ -151,11 +155,11 @@ export default function Profile() {

    Recent Activity

    diff --git a/web/src/services/UserService.ts b/web/src/services/UserService.ts index b1a1650..a24e682 100644 --- a/web/src/services/UserService.ts +++ b/web/src/services/UserService.ts @@ -1,8 +1,9 @@ import axios from "axios"; import type { ApiError } from "../types/api/error"; import type { User } from "../types/user"; -import type { GetAuthenticateUserFavoritesResponse, GetAuthenticateUserRecipesResponse, GetAuthenticateUserResponse } from "../types/api/user"; +import type { GetAuthenticateUserEngagementResponse, GetAuthenticateUserFavoritesResponse, GetAuthenticateUserRecipesResponse, GetAuthenticateUserResponse } from "../types/api/user"; import type { Recipe } from "../types/recipe"; +import type { Engagement } from "../types/engagement"; export async function GetAuthenticatedUser(): Promise { @@ -46,3 +47,17 @@ export async function GetAuthenticatedUserFavorites(): Promise { + const response = await axios.get("http://localhost:3000/v2/api/user/engagement"); + + if (response.data.status !== 200 || response.data.engagement === undefined) { + const err: ApiError = { + status: response.data.status, + message: response.data.message + }; + return err; + } + + return response.data.engagement; +} diff --git a/web/src/types/api/user.ts b/web/src/types/api/user.ts index c69dafc..0a0db86 100644 --- a/web/src/types/api/user.ts +++ b/web/src/types/api/user.ts @@ -1,3 +1,4 @@ +import type { Engagement } from "../engagement"; import type { Recipe } from "../recipe"; import type { User } from "../user"; @@ -18,3 +19,9 @@ export interface GetAuthenticateUserFavoritesResponse { message: string; favorites?: Recipe[]; } + +export interface GetAuthenticateUserEngagementResponse { + status: number; + message: string; + engagement?: Engagement[]; +}