Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VITE_AUTH_SERVER_URL=https://auth.dearborncodingclub.com
VITE_API_BASE_URL=http://localhost:8000
VITE_AUTH_SERVER_URL=http://localhost:8080
3 changes: 2 additions & 1 deletion .env.production
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VITE_AUTH_SERVER_URL=https://auth.dearborncodingclub.com
VITE_API_BASE_URL=https://api.dearborncodingclub.com
VITE_AUTH_SERVER_URL=https://auth.dearborncodingclub.com
41 changes: 37 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ Dearborn Coding Club Frontend is a dynamic, React-based website for the [Dearbor

## Table of Contents
1. [Architecture](#architecture)
2. [Running](#running)
2. [Environment Configuration](#environment-configuration)
3. [Running](#running)
* [Running locally](#running-locally)
* [Running from Docker Container](#running-from-the-gostatic-docker-container-locally)
3. [Building](#building-locally)
4. [Deploying](#deploying)
4. [Building](#building-locally)
5. [Deploying](#deploying)
* [Deploying to Fly.io](#deploying-to-flyio)
* [Deploying to Staging](#deploying-to-staging)
5. [(Re)generating TLS Certificates](#regenerating-tls-certificates)
6. [(Re)generating TLS Certificates](#regenerating-tls-certificates)

## Architecture
---
Expand Down Expand Up @@ -43,11 +44,40 @@ sequenceDiagram
end
```

## Environment Configuration
---

The frontend uses environment variables to configure API endpoints for different environments. Create a `.env` file in the root directory with the following variables:

### Local Development

For local development, create a `.env` file with:

```bash
VITE_API_BASE_URL=http://localhost:8000
VITE_AUTH_SERVER_URL=http://localhost:8080
```

These are the default values used if the environment variables are not set, so you can run the app locally without a `.env` file.

### Production

For production builds, set these environment variables:

```bash
VITE_API_BASE_URL=https://api.dearborncodingclub.com
VITE_AUTH_SERVER_URL=https://auth.dearborncodingclub.com
```

> [!NOTE]
> Environment variables prefixed with `VITE_` are exposed to the client-side code. Make sure these only contain public API endpoints, not sensitive credentials.

## Running
---

### Running locally
- Run `npm install`
- (Optional) Create a `.env` file with your local configuration (see [Environment Configuration](#environment-configuration))
- Run `npm run dev`

### Running from the goStatic docker container locally
Expand All @@ -61,6 +91,9 @@ sequenceDiagram

- Run `npm run build`

> [!NOTE]
> When building for production, ensure the environment variables `VITE_API_BASE_URL` and `VITE_AUTH_SERVER_URL` are set to production values. These are embedded at build time.

## Deploying
---

Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions src/config/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* API Configuration
*
* Centralized configuration for API endpoints.
* Uses environment variables with sensible defaults for local development.
*/

// Helper to get env var with fallback, explicitly checking for undefined/empty
const getEnvVar = (key: string, defaultValue: string): string => {
const value = (import.meta.env as Record<string, string | undefined>)[key];
return (value && typeof value === 'string' && value.trim() !== '') ? value : defaultValue;
};

export const API_BASE_URL = getEnvVar('VITE_API_BASE_URL', 'http://localhost:8000');
export const AUTH_SERVER_URL = getEnvVar('VITE_AUTH_SERVER_URL', 'http://localhost:8080');

2 changes: 1 addition & 1 deletion src/hooks/useRegisterForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useState } from "react"
import { toastType, useToastProvider } from "../providers/ToastProvider"
import { AUTH_SERVER_URL } from "../config/api"

const useRegisterForm = () => {
const AUTH_SERVER_URL = import.meta.env.VITE_AUTH_SERVER_URL;
const { pushToast } = useToastProvider();

const [errorMessage, setErrorMessage] = useState("");
Expand Down
5 changes: 3 additions & 2 deletions src/pages/Notes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom"
import "../css/theme.css"
import { CircleArrowLeft } from "lucide-react"
import { useAuthServiceProvider } from "../providers/AuthServiceProvider"
import { API_BASE_URL } from "../config/api"

interface ServerResponse {
message: string
Expand Down Expand Up @@ -31,7 +32,7 @@ const Notes: React.FC = () => {
const onClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();

const response = await fetch("https://api.dearborncodingclub.com/v2/notes/", {
const response = await fetch(`${API_BASE_URL}/v2/notes/`, {
method: "POST",
body: JSON.stringify({title: title, content: notes}),
headers: {
Expand All @@ -57,7 +58,7 @@ const Notes: React.FC = () => {
const fetchMessage = async (): Promise<void> => {
try {
const response = await fetch(
"https://api.dearborncodingclub.com/v2/notes/", {
`${API_BASE_URL}/v2/notes/`, {
method: "GET",
headers: {
"Content-type": "application/json; charset=UTF-8",
Expand Down
3 changes: 2 additions & 1 deletion src/pages/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import "../css/Profile.css"
import DummyProfilePicture from "../assets/dummy-profile.png"
import CircularProgressBar from "../components/CircularProgressBar"
import React, { useEffect } from "react"
import { API_BASE_URL } from "../config/api"

const Profile: React.FC = () => {

useEffect(() => {
const fetchProfileData = async () => {
const response = await fetch("https://api.dearborncodingclub.com/profile")
const response = await fetch(`${API_BASE_URL}/profile`)
const data = await response.json()
console.log(data)
};
Expand Down
3 changes: 1 addition & 2 deletions src/providers/AuthServiceProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { createContext, useState, useContext, useEffect } from 'react'
import { useLoadingProvider } from './LoadingProvider';
import { AUTH_SERVER_URL } from '../config/api';

interface AuthServiceContextType {
token: string | null;
Expand All @@ -11,8 +12,6 @@ const AuthServiceContext = createContext<AuthServiceContextType | null>(null)

export const AuthServiceProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {

const AUTH_SERVER_URL = import.meta.env.VITE_AUTH_SERVER_URL

const { startLoading, stopLoading } = useLoadingProvider()

const [token, setToken] = useState(localStorage.getItem("token"))
Expand Down