Skip to content

Commit

Permalink
feat: Dynamic project configuration per environment (#64)
Browse files Browse the repository at this point in the history
* feat: Dynamic project configuration per environment
* feat: Dynamic page titles
* Remove unused `manifest.json`
* docs: Update docs for `.env` config
  • Loading branch information
amattu2 authored Oct 7, 2023
1 parent 17a9ae0 commit ef0931f
Show file tree
Hide file tree
Showing 21 changed files with 169 additions and 40 deletions.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
REACT_APP_NAME=""
REACT_APP_DESCRIPTION=""
REACT_APP_SLOGAN=""
REACT_APP_API_URL=""
REACT_APP_MEDIA_API_URL=""
REACT_APP_MEDIA_CDN_URL=""
REACT_APP_API_CLIENT=""
7 changes: 7 additions & 0 deletions .github/workflows/cloudflare-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,18 @@ jobs:
run: npm ci

- name: Build
env:
REACT_APP_NAME: ${{ vars.REACT_APP_NAME }}
REACT_APP_SLOGAN: ${{ vars.REACT_APP_SLOGAN }}
REACT_APP_API_URL: ${{ vars.REACT_APP_API_URL }}
REACT_APP_MEDIA_API_URL: ${{ vars.REACT_APP_MEDIA_API_URL }}
REACT_APP_MEDIA_CDN_URL: ${{ vars.REACT_APP_MEDIA_CDN_URL }}
run: npm run build

- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: vinwiki
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ coverage/
.openapi-generator/

# Specific Files
.env
thunderEnvironment.json
thunderActivity.json
.openapi-generator-ignore
Expand Down
3 changes: 2 additions & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"MD033": false,
"MD025": false
"MD025": false,
"MD013": false
}
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Install dependencies
cd better-vinwiki && npm ci
```

Setup the `.env` file

```bash
cp .env.example .env
```

Run the application

```bash
Expand All @@ -37,6 +43,27 @@ npm start

Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

# Advanced Configuration

The default build will start out of the box, but needs to be tied to the correct
VINwiki deployment tier (e.g. DEV/PROD). These should be injected during the build
process.

Configuration Options (See [.env.example](./.env.example) for all options):

| Name | Description |
|:-|:-|
|`REACT_APP_NAME`|The name of the app. Used everywhere|
|`REACT_APP_DESCRIPTION`|The description built into the HTML5 meta tags|
|`REACT_APP_SLOGAN`|Sits under the App Name on the auth pages|
|`REACT_APP_API_URL`|Base URL for the VINwiki API. Should have a trailing `/` at the end|
|`REACT_APP_MEDIA_API_URL`|Base URL for the VINwiki Media API. Should have a trailing `/`|
|`REACT_APP_MEDIA_CDN_URL`|Base URL for the VINwiki Media CDN. Should have a trailing `/`|
|`REACT_APP_API_CLIENT`|The client name injected into a new post. Keep it simple and short|

See [src/config/AppConfig.ts](./src/config/AppConfig.ts) for the build defaults.
You likely will not want to leave them as the defaults.

# VINwiki REST API Docs

The OpenAPI Documentation for the VINwiki REST API can be found [here](./openapi.yml).
Expand Down
4 changes: 2 additions & 2 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="A reenvisioned and modernized VINwiki.com alternative web application client."
content="%REACT_APP_DESCRIPTION%"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Better VINwiki</title>
<title>%REACT_APP_NAME%</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
Expand Down
15 changes: 0 additions & 15 deletions public/manifest.json

This file was deleted.

1 change: 0 additions & 1 deletion public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
3 changes: 2 additions & 1 deletion src/components/CreatePost/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PlateDecoder from "../PlateDecoder/Dialog";
import ProfileAvatar from "../ProfileAvatar";
import { VehicleSearch } from "../Typeahead/VehicleSearch";
import { useFeedProvider } from "../../Providers/FeedProvider";
import { CONFIG } from "../../config/AppConfig";

type Props = {
vehicle?: Vehicle;
Expand Down Expand Up @@ -181,7 +182,7 @@ const CreatePost: FC<Props> = ({ vehicle }: Props) => {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
client: "better-vinwiki",
client: CONFIG.API_CLIENT,
event_date: watch("event_date") ? dayjs(watch("event_date")).toISOString() : "",
locale: watch("locale"),
mileage: watch("mileage"),
Expand Down
4 changes: 2 additions & 2 deletions src/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useAuthProvider } from '../../Providers/AuthProvider';
import { useNotificationCountProvider } from '../../Providers/NotificationCountProvider';
import { Notifications } from '../Notifications';
import { FollowersDrawer } from '../FollowersDrawer';
import { MEDIA_CDN } from '../../config/Endpoints';
import { MEDIA_CDN_URL } from '../../config/Endpoints';

const StyledBox = styled(Box)({
padding: "32px 12px",
Expand Down Expand Up @@ -97,7 +97,7 @@ const Sidebar: FC = () => {
component={StyledLink}
to={`/profile/${profile.uuid}`}
sx={{ width: 36, height: 36 }}
src={profile.avatar ? `${MEDIA_CDN}${profile.avatar}` : undefined}
src={profile.avatar ? `${MEDIA_CDN_URL}${profile.avatar}` : undefined}
>
{profile?.username?.charAt(0).toUpperCase()}
</Avatar>
Expand Down
9 changes: 9 additions & 0 deletions src/config/AppConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const CONFIG: AppConfig = {
name: process.env.REACT_APP_NAME || "React App",
description: process.env.REACT_APP_DESCRIPTION || "",
slogan: process.env.REACT_APP_SLOGAN || "",
API_URL: process.env.REACT_APP_API_URL || "http://localhost:8080/",
MEDIA_API_URL: process.env.REACT_APP_MEDIA_API_URL || "http://localhost:8081/",
MEDIA_CDN_URL: process.env.REACT_APP_MEDIA_CDN_URL || "http://localhost:8082/",
API_CLIENT: process.env.REACT_APP_API_CLIENT || "react-app",
};
13 changes: 6 additions & 7 deletions src/config/Endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const API_URL: string = 'https://rest.vinwiki.com/';
export const MEDIA_URL: string = "https://media.vinwiki.com/media/";
export const MEDIA_CDN: string = "https://media-cdn.vinwiki.com/";
import { CONFIG } from "./AppConfig";

export const { API_URL, MEDIA_API_URL, MEDIA_CDN_URL } = CONFIG;

export const DEFAULT_DATE = "1970-01-01T00:00:00+00:00";
export const DEFAULT_VEHICLE_SRC = "https://media.vinwiki.com/static/img/placeholders/car_100_sq.jpg";
Expand All @@ -12,7 +12,6 @@ export const ENDPOINTS = {
reset_password: `${API_URL}auth/pwreset`,
logout: `${API_URL}auth/logout`,
register: `${API_URL}auth/preregister`,
// TODO: Password Change Endpoint...

/* Person Endpoints */
profile: `${API_URL}person/profile/`,
Expand Down Expand Up @@ -68,9 +67,9 @@ export const ENDPOINTS = {

export const MEDIA_ENDPOINTS = {
/* Vehicle Endpoints */
vehicle_image_add: `${MEDIA_URL}add/photo/vehicle/`,
vehicle_image: `${MEDIA_URL}photo/vehicle/`,
person_image_add: `${MEDIA_URL}photo/person/`,
vehicle_image_add: `${MEDIA_API_URL}add/photo/vehicle/`,
vehicle_image: `${MEDIA_API_URL}photo/vehicle/`,
person_image_add: `${MEDIA_API_URL}photo/person/`,
};

export const STATUS_OK = "ok";
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/usePageTitle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useEffect } from "react";
import { CONFIG } from "../config/AppConfig";

/**
* Exposes a hook to set and restore the page title
*
* @param title The new title to set
* @param [suffix] Include the application name suffix
* @param [restore] Restore the title on unmount
*/
const usePageTitle = (title: string, suffix: boolean = true, restore: boolean = true): void => {
// Update title on mount
useEffect(() => {
document.title = suffix ? `${title} - ${CONFIG.name}` : title;
}, [title]);

// Revert on unmount if requested
useEffect(() => {
if (!restore) {
return () => {};
}

return () => document.title = CONFIG.name;
}, []);
};

export default usePageTitle;
7 changes: 6 additions & 1 deletion src/pages/forgotPassword/Controller.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from "react";
import ForgotView from "./View";
import usePageTitle from "../../hooks/usePageTitle";

const ForgotController = () => <ForgotView />;
const ForgotController = () => {
usePageTitle("Forgot Password");

return (<ForgotView />);
};

export default ForgotController;
5 changes: 3 additions & 2 deletions src/pages/forgotPassword/View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Box, Button, Stack, TextField, Typography, styled } from "@mui/material
import backgroundImage from "../../assets/images/shop-1864x1400.jpg";
import Loader from "../../components/Loader";
import { ENDPOINTS, STATUS_OK } from "../../config/Endpoints";
import { CONFIG } from "../../config/AppConfig";

type FormInput = {
email: string;
Expand Down Expand Up @@ -137,10 +138,10 @@ const ForgotView = () => {
<FormContainer alignItems="center" justifyContent="center">
<StyledHeaderBox>
<StyledHeader variant="h3">
Better VINwiki
{CONFIG.name}
</StyledHeader>
<StyledSubtitle variant="subtitle1">
A reimagined VINwiki web experience.
{CONFIG.slogan}
</StyledSubtitle>
</StyledHeaderBox>
<StyledFormBox component="form" onSubmit={handleSubmit(onSubmit)}>
Expand Down
7 changes: 6 additions & 1 deletion src/pages/login/Controller.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from "react";
import LoginView from "./View";
import usePageTitle from "../../hooks/usePageTitle";

const LoginController = () => <LoginView />;
const LoginController = () => {
usePageTitle("Login");

return <LoginView />;
};

export default LoginController;
5 changes: 3 additions & 2 deletions src/pages/login/View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import backgroundImage from "../../assets/images/shop-1864x1400.jpg";
import Loader from "../../components/Loader";
import { CacheKeys } from "../../config/Cache";
import { ENDPOINTS, STATUS_OK } from "../../config/Endpoints";
import { CONFIG } from "../../config/AppConfig";

type Inputs = {
username: string,
Expand Down Expand Up @@ -139,10 +140,10 @@ const LoginView = () => {
<FormContainer alignItems="center" justifyContent="center">
<StyledHeaderBox>
<StyledHeader variant="h3">
Better VINwiki
{CONFIG.name}
</StyledHeader>
<StyledSubtitle variant="subtitle1">
A reimagined VINwiki web experience.
{CONFIG.slogan}
</StyledSubtitle>
</StyledHeaderBox>
<StyledFormBox component="form" onSubmit={handleSubmit(onSubmit)}>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/profile/View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import useProfileListsLookup from "../../hooks/useProfileListsLookup";
import useProfileLookup, { LookupStatus as ProfileProviderStatus } from "../../hooks/useProfileLookup";
import { mapPostsToDate } from "../../utils/feed";
import { HyperlinkRegexNG } from "../../config/RegEx";
import { MEDIA_CDN } from "../../config/Endpoints";
import { MEDIA_CDN_URL } from "../../config/Endpoints";

type Props = {
uuid: string;
Expand Down Expand Up @@ -189,7 +189,7 @@ const View: FC<Props> = ({ uuid }: Props) => {

<StyledProfileDetails direction="column" gap={2}>
<Stack direction="row" alignItems="center" justifyContent="flex-start" gap={2}>
<StyledProfileAvatar username={profile.username} avatar={`${MEDIA_CDN}${profile.avatar}`} rounded />
<StyledProfileAvatar username={profile.username} avatar={`${MEDIA_CDN_URL}${profile.avatar}`} rounded />
<Stack direction="column" alignItems="flex-start" justifyContent="center" gap={1}>
<Typography variant="h3" fontSize={18} fontWeight="bold">{`@${profile.username}`}</Typography>
{profile.bio ? <GenericText content={profile.bio} /> : null}
Expand Down
7 changes: 6 additions & 1 deletion src/pages/register/Controller.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import React from "react";
import RegisterView from "./View";
import usePageTitle from "../../hooks/usePageTitle";

const RegisterController = () => <RegisterView />;
const RegisterController = () => {
usePageTitle("Register");

return (<RegisterView />);
};

export default RegisterController;
5 changes: 3 additions & 2 deletions src/pages/register/View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Box, Button, Stack, TextField, Typography, styled } from "@mui/material
import backgroundImage from "../../assets/images/shop-1864x1400.jpg";
import Loader from "../../components/Loader";
import { ENDPOINTS, STATUS_ERROR, STATUS_OK } from "../../config/Endpoints";
import { CONFIG } from "../../config/AppConfig";

type FormInput = {
email: string;
Expand Down Expand Up @@ -138,10 +139,10 @@ const RegisterView = () => {
<FormContainer alignItems="center" justifyContent="center">
<StyledHeaderBox>
<StyledHeader variant="h3">
Better VINwiki
{CONFIG.name}
</StyledHeader>
<StyledSubtitle variant="subtitle1">
A reimagined VINwiki web experience.
{CONFIG.slogan}
</StyledSubtitle>
</StyledHeaderBox>
<StyledFormBox component="form" onSubmit={handleSubmit(onSubmit)}>
Expand Down
48 changes: 48 additions & 0 deletions src/types/AppConfig.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* The strict type definition for the Application configuration
*/
type AppConfig = {
/**
* The name of the application
*
* Used by:
* - Page titles
* - Auth page banners
* - etc
*/
name: string;
/**
* The HTML meta description of the application
*
* Used by:
* - *Nothing yet*
*/
description: string;
/**
* The slogan of the application
*
* Visible under the name in the header.
*/
slogan: string;
/**
* The base URL for the API server
*
* NOTE: Should end with a trailing slash
*/
API_URL: string;
/**
* The base URL for the media API server
*
* NOTE: Should end with a trailing slash
*/
MEDIA_API_URL: string;
/**
* The base URL for the media CDN server
*/
MEDIA_CDN_URL: string;
/**
* The name of the client passed in the `client` property of
* a new Feed Post
*/
API_CLIENT: string;
};

0 comments on commit ef0931f

Please sign in to comment.