(FEAT): Deployed! Need to work on the CI/CD!
This commit is contained in:
parent
6bbd58b471
commit
f027a16b8c
55
Dockerfile
55
Dockerfile
@ -1,57 +1,14 @@
|
||||
# Fetch stage
|
||||
FROM golang:latest AS fetch-stage
|
||||
|
||||
COPY . /app
|
||||
FROM golang:1.25-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN go mod tidy
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Generate stage
|
||||
FROM ghcr.io/a-h/templ:latest AS generate-stage
|
||||
COPY . .
|
||||
|
||||
COPY --chown=65532:65532 . /app
|
||||
RUN go build -o server ./cmd/web/main.go
|
||||
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
|
||||
RUN ["templ", "generate"]
|
||||
|
||||
# Generate stage two
|
||||
|
||||
FROM node:lts-alpine AS tailwind-build-stage
|
||||
|
||||
COPY --from=generate-stage /app /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install tailwindcss @tailwindcss/cli && npx @tailwindcss/cli -i ./web/static/css/main.css -o ./web/static/css/tailwind.css --minify -c ./tailwind.config.js
|
||||
|
||||
|
||||
# Build stage
|
||||
FROM golang:latest AS build-stage
|
||||
|
||||
COPY --from=tailwind-build-stage /app /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN go mod tidy
|
||||
RUN go mod download
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /entrypoint /app/cmd/web/main.go
|
||||
|
||||
# Deploy.
|
||||
FROM gcr.io/distroless/static-debian11 AS release-stage
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=build-stage /entrypoint /entrypoint
|
||||
|
||||
COPY --from=build-stage /app/web/static /web/static
|
||||
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
USER nonroot:nonroot
|
||||
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
CMD ["./server"]
|
||||
|
||||
57
Dockerfile.old
Normal file
57
Dockerfile.old
Normal file
@ -0,0 +1,57 @@
|
||||
# Fetch stage
|
||||
FROM golang:latest AS fetch-stage
|
||||
|
||||
COPY . /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN go mod tidy
|
||||
RUN go mod download
|
||||
|
||||
# Generate stage
|
||||
FROM ghcr.io/a-h/templ:latest AS generate-stage
|
||||
|
||||
COPY --chown=65532:65532 . /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN ["templ", "generate"]
|
||||
|
||||
# Generate stage two
|
||||
|
||||
FROM node:lts-alpine AS tailwind-build-stage
|
||||
|
||||
COPY --from=generate-stage /app /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install tailwindcss @tailwindcss/cli && npx @tailwindcss/cli -i ./web/static/css/main.css -o ./web/static/css/tailwind.css --minify -c ./tailwind.config.js
|
||||
|
||||
|
||||
# Build stage
|
||||
FROM golang:latest AS build-stage
|
||||
|
||||
COPY --from=tailwind-build-stage /app /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN go mod tidy
|
||||
RUN go mod download
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /entrypoint /app/cmd/web/main.go
|
||||
|
||||
# Deploy.
|
||||
FROM gcr.io/distroless/static-debian11 AS release-stage
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=build-stage /entrypoint /entrypoint
|
||||
|
||||
COPY --from=build-stage /app/web/static /web/static
|
||||
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
USER nonroot:nonroot
|
||||
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
@ -29,11 +29,13 @@ func (s *Server) GoogleCallbackHandlerV2(ctx *gin.Context) {
|
||||
code string = ctx.Query("code")
|
||||
)
|
||||
|
||||
domain := s.deps.EnvironmentConfig.FrontendDomain
|
||||
|
||||
if jwt, err := s.deps.AuthService.GoogleAuthSuccess(state, code); err != nil {
|
||||
url := fmt.Sprintf("http://localhost:5173/v2/web/login?error=%s", url.QueryEscape(err.Error()))
|
||||
url := fmt.Sprintf("%s/v2/web/login?error=%s", domain, url.QueryEscape(err.Error()))
|
||||
ctx.Redirect(http.StatusSeeOther, url)
|
||||
} else {
|
||||
url := "http://localhost:5173/v2/web/home"
|
||||
url := fmt.Sprintf("%s/v2/web/home", domain)
|
||||
s.SetCookie(ctx, "jwt_token", jwt, time.Hour*24*7)
|
||||
ctx.Redirect(http.StatusSeeOther, url)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -20,7 +21,7 @@ func (s *Server) SetCookie(ctx *gin.Context, name, value string, duration time.D
|
||||
path string = "/"
|
||||
httpOnly bool = false // NOTE: Should use false so React can see it!
|
||||
maxAge int
|
||||
secure bool = false
|
||||
secure bool = true
|
||||
domain string = ""
|
||||
)
|
||||
|
||||
@ -35,9 +36,12 @@ func (s *Server) SetCookie(ctx *gin.Context, name, value string, duration time.D
|
||||
maxAge = int(time.Until(time.Now().Add(duration)).Seconds())
|
||||
}
|
||||
|
||||
// TODO: This whole system is stupid now
|
||||
if s.deps.EnvironmentConfig.Environment == "prod" {
|
||||
secure = true
|
||||
domain = s.deps.EnvironmentConfig.Domain
|
||||
// domain = "potion.gophernest"
|
||||
// domain = s.deps.EnvironmentConfig.Domain
|
||||
domain = ".gophernest.net"
|
||||
|
||||
} else if s.deps.EnvironmentConfig.Environment == "dev" {
|
||||
secure = false
|
||||
@ -45,5 +49,6 @@ func (s *Server) SetCookie(ctx *gin.Context, name, value string, duration time.D
|
||||
domain = "localhost"
|
||||
}
|
||||
|
||||
ctx.SetSameSite(http.SameSiteNoneMode)
|
||||
ctx.SetCookie(name, value, maxAge, path, domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ func Init(port int) *Server {
|
||||
|
||||
// Setup the CORS settings and active them
|
||||
// server.config.AllowAllOrigins = true
|
||||
server.config.AllowOrigins = []string{"http://localhost:5173"}
|
||||
server.config.AllowOrigins = []string{"http://localhost:5173", "https://potion.gophernest.net"}
|
||||
server.config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE"}
|
||||
server.config.AllowHeaders = []string{"Origin", "Content-Type", "Authorization"}
|
||||
server.config.AllowCredentials = true
|
||||
|
||||
@ -23,6 +23,7 @@ type EnvironmentConfig struct {
|
||||
DatabaseUrl string
|
||||
Environment string
|
||||
Domain string
|
||||
FrontendDomain string
|
||||
}
|
||||
|
||||
// InjectedDependencies is a collection of dependencies that are injected into the application. They
|
||||
@ -81,16 +82,25 @@ func LoadEnvironment() (*EnvironmentConfig, error) {
|
||||
}
|
||||
|
||||
var domain string
|
||||
var frontendDomain string
|
||||
if env == "dev" {
|
||||
domain = os.Getenv("DOMAIN_DEV")
|
||||
if domain == "" {
|
||||
return nil, fmt.Errorf("DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.")
|
||||
}
|
||||
frontendDomain = os.Getenv("FRONTEND_DOMAIN_DEV")
|
||||
if frontendDomain == "" {
|
||||
return nil, fmt.Errorf("FRONTEND_DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.")
|
||||
}
|
||||
} else if env == "prod" {
|
||||
domain = os.Getenv("DOMAIN_PROD")
|
||||
if domain == "" {
|
||||
return nil, fmt.Errorf("DOMAIN_PROD environment variable is required when ENVIRONMENT is 'prod'.")
|
||||
}
|
||||
frontendDomain = os.Getenv("FRONTEND_DOMAIN_PROD")
|
||||
if frontendDomain == "" {
|
||||
return nil, fmt.Errorf("FRONTEND_DOMAIN_PROD environment variable is required when ENVIRONMENT is 'dev'.")
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.")
|
||||
}
|
||||
@ -117,8 +127,11 @@ func LoadEnvironment() (*EnvironmentConfig, error) {
|
||||
DatabaseUrl: dbUrl,
|
||||
Environment: env,
|
||||
Domain: domain,
|
||||
FrontendDomain: frontendDomain,
|
||||
}
|
||||
|
||||
fmt.Printf("Environment Config: %+v\n", cfg)
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
||||
2
web/.gitignore
vendored
2
web/.gitignore
vendored
@ -22,3 +22,5 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
||||
|
||||
@ -75,8 +75,11 @@ export default function IngredientItem({ classes, ingredient, onChange, removeIn
|
||||
</button>
|
||||
<div
|
||||
tabIndex={-1}
|
||||
onPointerDown={(e) => controls.start(e)}
|
||||
className="p-1 md:p-0 cursor-pointer"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault();
|
||||
controls.start(e);
|
||||
}}
|
||||
className="p-1 md:p-0 cursor-pointer touch-none"
|
||||
>
|
||||
<DragIconSmall />
|
||||
</div>
|
||||
|
||||
@ -41,7 +41,13 @@ export default function IngredientSection({ section, onChange, removeIngredientS
|
||||
>
|
||||
<DeleteIconSmall />
|
||||
</button>
|
||||
<div className="p-0 cursor-pointer" onPointerDown={(e) => controls.start(e)}>
|
||||
<div
|
||||
className="p-0 cursor-pointer touch-none"
|
||||
onPointerDown={(e) => {
|
||||
e.preventDefault();
|
||||
controls.start(e);
|
||||
}}
|
||||
>
|
||||
<DragIconSmall />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -52,7 +52,13 @@ export default function InstructionElement({ instruction, index, allowDelete, on
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="p-2 pr-0 cursor-grab" onPointerDown={e => controls.start(e)}>
|
||||
<div
|
||||
className="p-2 pr-0 cursor-grab touch-none"
|
||||
onPointerDown={e => {
|
||||
e.preventDefault();
|
||||
controls.start(e);
|
||||
}}
|
||||
>
|
||||
<DragIconSmall />
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useEffect, type ChangeEvent, type Dispatch, type InputHTMLAttributes, type SetStateAction } from "react";
|
||||
import { type ChangeEvent, type Dispatch, type InputHTMLAttributes, type SetStateAction } from "react";
|
||||
import type { CreateRecipeFormDirtyEntries } from "../../pages/Create";
|
||||
|
||||
interface RecipeCreateFormInputProps
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import axios from "axios";
|
||||
import type { GetGoogleAuthUrlResponse, LogoutResponse } from "../types/api/auth";
|
||||
import type { ApiError } from "../types/api/error";
|
||||
import { GetBackendUrl } from "./util";
|
||||
|
||||
const BACKEND_URL = GetBackendUrl();
|
||||
|
||||
|
||||
export async function GetGoogleAuthUrl(): Promise<string | ApiError> {
|
||||
const response = await axios.get<GetGoogleAuthUrlResponse>("http://localhost:3000/v2/api/auth/login");
|
||||
const response = await axios.get<GetGoogleAuthUrlResponse>(`${BACKEND_URL}/v2/api/auth/login`);
|
||||
|
||||
if (response.status !== 200) {
|
||||
const err: ApiError = {
|
||||
@ -18,7 +21,7 @@ export async function GetGoogleAuthUrl(): Promise<string | ApiError> {
|
||||
}
|
||||
|
||||
export async function Logout(): Promise<void> {
|
||||
const response = await axios.get<LogoutResponse>("http://localhost:3000/v2/api/auth/logout");
|
||||
const response = await axios.get<LogoutResponse>(`${BACKEND_URL}/v2/api/auth/logout`);
|
||||
|
||||
// This should never happen
|
||||
if (response.status !== 204)
|
||||
|
||||
@ -2,9 +2,12 @@ import axios from "axios";
|
||||
import type { ApiError } from "../types/api/error";
|
||||
import type { Engagement } from "../types/engagement";
|
||||
import type { EngagementFavoriteRecipeResponse, EngagementMakeRecipeResponse, EngagementShareRecipeResponse, EngagementViewRecipeResponse } from "../types/api/engagement";
|
||||
import { GetBackendUrl } from "./util";
|
||||
|
||||
const BACKEND_URL = GetBackendUrl();
|
||||
|
||||
export async function EngagementViewRecipe(recipeId: number): Promise<Engagement | ApiError> {
|
||||
const response = await axios.post<EngagementViewRecipeResponse>(`http://localhost:3000/v2/api/engagement/view/${recipeId}`);
|
||||
const response = await axios.post<EngagementViewRecipeResponse>(`${BACKEND_URL}/v2/api/engagement/view/${recipeId}`);
|
||||
|
||||
if (response.status !== 200 || response.data.engagement === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -18,7 +21,7 @@ export async function EngagementViewRecipe(recipeId: number): Promise<Engagement
|
||||
}
|
||||
|
||||
export async function EngagementShareRecipe(recipeId: number): Promise<Engagement | ApiError> {
|
||||
const response = await axios.post<EngagementShareRecipeResponse>(`http://localhost:3000/v2/api/engagement/share/${recipeId}`);
|
||||
const response = await axios.post<EngagementShareRecipeResponse>(`${BACKEND_URL}/v2/api/engagement/share/${recipeId}`);
|
||||
|
||||
if (response.status !== 200 || response.data.engagement === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -32,7 +35,7 @@ export async function EngagementShareRecipe(recipeId: number): Promise<Engagemen
|
||||
}
|
||||
|
||||
export async function EngagementFavoriteRecipe(recipeId: number): Promise<Engagement | ApiError> {
|
||||
const response = await axios.post<EngagementFavoriteRecipeResponse>(`http://localhost:3000/v2/api/engagement/favorite/${recipeId}`);
|
||||
const response = await axios.post<EngagementFavoriteRecipeResponse>(`${BACKEND_URL}/v2/api/engagement/favorite/${recipeId}`);
|
||||
|
||||
if (response.status !== 200 || response.data.engagement === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -46,7 +49,7 @@ export async function EngagementFavoriteRecipe(recipeId: number): Promise<Engage
|
||||
}
|
||||
|
||||
export async function EngagementMakeRecipe(recipeId: number): Promise<Engagement | ApiError> {
|
||||
const response = await axios.post<EngagementMakeRecipeResponse>(`http://localhost:3000/v2/api/engagement/make/${recipeId}`);
|
||||
const response = await axios.post<EngagementMakeRecipeResponse>(`${BACKEND_URL}/v2/api/engagement/make/${recipeId}`);
|
||||
|
||||
if (response.status !== 200 || response.data.engagement === undefined) {
|
||||
const err: ApiError = {
|
||||
|
||||
@ -3,10 +3,13 @@ import type { CreateRecipeRequest, CreateRecipeResponse, GetRecipeOfTheWeekRespo
|
||||
import type { Recipe } from "../types/recipe";
|
||||
import type { ApiError } from "../types/api/error";
|
||||
import type { SearchFilters } from "../types/search";
|
||||
import { GetBackendUrl } from "./util";
|
||||
|
||||
const BACKEND_URL = GetBackendUrl();
|
||||
|
||||
|
||||
export async function GetRecipeOfTheWeek(): Promise<Recipe | ApiError> {
|
||||
const response = await axios.get<GetRecipeOfTheWeekResponse>("http://localhost:3000/v2/api/recipe/of-the-week");
|
||||
const response = await axios.get<GetRecipeOfTheWeekResponse>(`${BACKEND_URL}/v2/api/recipe/of-the-week`);
|
||||
|
||||
if (response.status !== 200 || response.data.recipe === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -20,7 +23,7 @@ export async function GetRecipeOfTheWeek(): Promise<Recipe | ApiError> {
|
||||
}
|
||||
|
||||
export async function GetRecipe(id: number): Promise<Recipe | ApiError> {
|
||||
const response = await axios.get<GetRecipeResponse>(`http://localhost:3000/v2/api/recipe/${id}`);
|
||||
const response = await axios.get<GetRecipeResponse>(`${BACKEND_URL}/v2/api/recipe/${id}`);
|
||||
|
||||
if (response.status !== 200 || response.data.recipe === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -34,7 +37,7 @@ export async function GetRecipe(id: number): Promise<Recipe | ApiError> {
|
||||
}
|
||||
|
||||
export async function SearchRecipes(filters: SearchFilters): Promise<Recipe[] | ApiError> {
|
||||
const response = await axios.post<SearchRecipesResponse>("http://localhost:3000/v2/api/recipe/search", filters);
|
||||
const response = await axios.post<SearchRecipesResponse>(`${BACKEND_URL}/v2/api/recipe/search`, filters);
|
||||
|
||||
if (response.status !== 200 || response.data.recipes === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -48,7 +51,7 @@ export async function SearchRecipes(filters: SearchFilters): Promise<Recipe[] |
|
||||
}
|
||||
|
||||
export async function CreateRecipe(data: CreateRecipeRequest): Promise<Recipe | ApiError> {
|
||||
const response = await axios.post<CreateRecipeResponse>("http://localhost:3000/v2/api/recipe", data);
|
||||
const response = await axios.post<CreateRecipeResponse>(`${BACKEND_URL}/v2/api/recipe`, data);
|
||||
|
||||
if (response.status !== 200 || response.data.recipe === undefined) {
|
||||
const err: ApiError = {
|
||||
|
||||
@ -4,9 +4,12 @@ import type { User } from "../types/user";
|
||||
import type { GetAuthenticateUserEngagementResponse, GetAuthenticateUserFavoritesResponse, GetAuthenticateUserMadeRecipesResponse, GetAuthenticateUserRecipesResponse, GetAuthenticateUserResponse, GetAuthenticateUserViewedRecipesResponse, GetUserResponse } from "../types/api/user";
|
||||
import type { Recipe } from "../types/recipe";
|
||||
import type { Engagement } from "../types/engagement";
|
||||
import { GetBackendUrl } from "./util";
|
||||
|
||||
const BACKEND_URL = GetBackendUrl();
|
||||
|
||||
export async function GetUser(id: number): Promise<User | ApiError> {
|
||||
const response = await axios.get<GetUserResponse>(`http://localhost:3000/v2/api/user/${id}`);
|
||||
const response = await axios.get<GetUserResponse>(`${BACKEND_URL}/v2/api/user/${id}`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.user === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -20,7 +23,7 @@ export async function GetUser(id: number): Promise<User | ApiError> {
|
||||
}
|
||||
|
||||
export async function GetAuthenticatedUser(): Promise<User | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserResponse>("http://localhost:3000/v2/api/user");
|
||||
const response = await axios.get<GetAuthenticateUserResponse>(`${BACKEND_URL}/v2/api/user`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.user === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -34,7 +37,7 @@ export async function GetAuthenticatedUser(): Promise<User | ApiError> {
|
||||
}
|
||||
|
||||
export async function GetAuthenticatedUserRecipes(): Promise<Recipe[] | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserRecipesResponse>("http://localhost:3000/v2/api/user/recipes");
|
||||
const response = await axios.get<GetAuthenticateUserRecipesResponse>(`${BACKEND_URL}/v2/api/user/recipes`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.recipes === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -48,7 +51,7 @@ export async function GetAuthenticatedUserRecipes(): Promise<Recipe[] | ApiError
|
||||
}
|
||||
|
||||
export async function GetAuthenticatedUserFavorites(): Promise<Recipe[] | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserFavoritesResponse>("http://localhost:3000/v2/api/user/favorites");
|
||||
const response = await axios.get<GetAuthenticateUserFavoritesResponse>(`${BACKEND_URL}/v2/api/user/favorites`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.favorites === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -62,7 +65,7 @@ export async function GetAuthenticatedUserFavorites(): Promise<Recipe[] | ApiErr
|
||||
}
|
||||
|
||||
export async function GetAuthenticatedUserEngagement(): Promise<Engagement[] | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserEngagementResponse>("http://localhost:3000/v2/api/user/engagement");
|
||||
const response = await axios.get<GetAuthenticateUserEngagementResponse>(`${BACKEND_URL}/v2/api/user/engagement`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.engagement === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -76,7 +79,7 @@ export async function GetAuthenticatedUserEngagement(): Promise<Engagement[] | A
|
||||
}
|
||||
|
||||
export async function GetAuthenticatedUserMadeRecipes(): Promise<Recipe[] | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserMadeRecipesResponse>("http://localhost:3000/v2/api/user/recipes/made");
|
||||
const response = await axios.get<GetAuthenticateUserMadeRecipesResponse>(`${BACKEND_URL}/v2/api/user/recipes/made`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.recipes === undefined) {
|
||||
const err: ApiError = {
|
||||
@ -90,7 +93,7 @@ export async function GetAuthenticatedUserMadeRecipes(): Promise<Recipe[] | ApiE
|
||||
}
|
||||
|
||||
export async function GetAuthenticateUserViewedRecipes(): Promise<Recipe[] | ApiError> {
|
||||
const response = await axios.get<GetAuthenticateUserViewedRecipesResponse>("http://localhost:3000/v2/api/user/recipes/viewed");
|
||||
const response = await axios.get<GetAuthenticateUserViewedRecipesResponse>(`${BACKEND_URL}/v2/api/user/recipes/viewed`);
|
||||
|
||||
if (response.data.status !== 200 || response.data.recipes === undefined) {
|
||||
const err: ApiError = {
|
||||
|
||||
15
web/src/services/util.ts
Normal file
15
web/src/services/util.ts
Normal file
@ -0,0 +1,15 @@
|
||||
const ENV = import.meta.env;
|
||||
|
||||
export function GetBackendUrl(): string {
|
||||
const env = ENV.VITE_ENVIRONMENT as string;
|
||||
if (!env) return "";
|
||||
|
||||
switch (env.toLowerCase()) {
|
||||
case "dev":
|
||||
return ENV.VITE_DOMAIN_DEV as string;
|
||||
case "prod":
|
||||
return ENV.VITE_DOMAIN_PROD as string;
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user