set up demo mode
This commit is contained in:
parent
9aac6e0eff
commit
04bfdd0c8f
10 changed files with 93 additions and 16 deletions
|
@ -10,7 +10,7 @@ app.use(express.json());
|
|||
// ####### ROUTES #######
|
||||
app.get("/backend/test", async (req, res) => {
|
||||
console.log("test");
|
||||
res.json({ test: "test" });
|
||||
res.json({ env: process.env.NODE_ENV });
|
||||
});
|
||||
// ### GET ALL RECIPES ###
|
||||
app.get("/backend/recipes", async (req, res) => {
|
||||
|
@ -81,6 +81,7 @@ app.get("/backend/recipe/:id", async (req, res) => {
|
|||
|
||||
// ### ADD RECIPE ###
|
||||
app.post("/backend/add-recipe", async (req, res) => {
|
||||
if (process.env.NODE_ENV === 'demo') { return; };
|
||||
const { name, author, cuisine, stars, ingredients, steps, prep_minutes, cook_minutes } = req.body;
|
||||
try {
|
||||
const [id] = await db("recipes").insert(
|
||||
|
@ -118,6 +119,7 @@ app.post("/backend/add-recipe", async (req, res) => {
|
|||
|
||||
// ### SET STARS ###
|
||||
app.post("/backend/set-stars", async (req, res) => {
|
||||
if (process.env.NODE_ENV === 'demo') { return; };
|
||||
const { id, stars } = req.body;
|
||||
try {
|
||||
await db("recipes").where({ id: id }).update({ stars: stars });
|
||||
|
@ -130,6 +132,7 @@ app.post("/backend/set-stars", async (req, res) => {
|
|||
|
||||
// ### DELETE RECIPE ###
|
||||
app.delete("/backend/delete-recipe", async (req, res) => {
|
||||
if (process.env.NODE_ENV === 'demo') { return; };
|
||||
const { id } = req.body;
|
||||
try {
|
||||
await db("recipe_steps").where({ recipe_id: id }).del();
|
||||
|
|
|
@ -20,6 +20,25 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
|
||||
demo: {
|
||||
client: "postgresql",
|
||||
connection: {
|
||||
host: "db",
|
||||
port: process.env.DB_PORT,
|
||||
database: process.env.DB_NAME,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
},
|
||||
pool: {
|
||||
min: 2,
|
||||
max: 10,
|
||||
},
|
||||
migrations: {
|
||||
tableName: "knex_migrations",
|
||||
directory: "./migrations",
|
||||
},
|
||||
},
|
||||
|
||||
production: {
|
||||
client: "postgresql",
|
||||
connection: {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "node backendServer.js",
|
||||
"demo": "node backendServer.js",
|
||||
"production": "node backendServer.js"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
db:
|
||||
container_name: recipes_postgres
|
||||
container_name: recipes_postgres_${ID}
|
||||
image: docker.io/library/postgres:17
|
||||
# restart: always
|
||||
env_file:
|
||||
|
@ -15,13 +15,13 @@ services:
|
|||
- ./postgres/db:/var/lib/postgresql/data
|
||||
backend:
|
||||
image: recipes_backend
|
||||
container_name: recipes_backend
|
||||
container_name: recipes_backend_${ID}
|
||||
build:
|
||||
context: ./backend
|
||||
args:
|
||||
NODE_ENV: ${NODE_ENV}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "${BACKEND_PORT}:3000"
|
||||
volumes:
|
||||
- ./backend:/usr/src/app
|
||||
environment:
|
||||
|
@ -31,13 +31,13 @@ services:
|
|||
- DB_NAME=${DB_NAME}
|
||||
frontend:
|
||||
image: recipes_frontend
|
||||
container_name: recipes_frontend
|
||||
container_name: recipes_frontend_${ID}
|
||||
build:
|
||||
context: ./backend
|
||||
args:
|
||||
NODE_ENV: ${NODE_ENV}
|
||||
ports:
|
||||
- "8081:80"
|
||||
- "${FRONTEND_PORT}:80"
|
||||
volumes:
|
||||
- ./frontend:/usr/src/app
|
||||
environment:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"scripts": {
|
||||
"dev": "vite --host 0.0.0.0 --port 80",
|
||||
"production": "vite --host 0.0.0.0 --port 80",
|
||||
"demo": "vite --host 0.0.0.0 --port 80",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { type RecipeSmall } from "../types/Recipe"
|
||||
import Modal from '../components/Modal.tsx'
|
||||
import DemoModal from '../components/DemoModal.tsx'
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface CookbookRecipeTileProps {
|
||||
|
@ -9,13 +10,19 @@ interface CookbookRecipeTileProps {
|
|||
}
|
||||
|
||||
function CookbookRecipeTile({ recipe, handleDelete }: CookbookRecipeTileProps) {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false);
|
||||
const [showDemoModal, setShowDemoModal] = useState(false);
|
||||
|
||||
const openModal = () => { setIsModalOpen(true) };
|
||||
const closeModal = () => { setIsModalOpen(false) };
|
||||
const openModal = () => { setShowConfirmModal(true) };
|
||||
const closeModal = () => { setShowConfirmModal(false) };
|
||||
const confirmDelete = () => {
|
||||
handleDelete(recipe.id);
|
||||
closeModal();
|
||||
if (process.env.NODE_ENV === 'demo') {
|
||||
closeModal();
|
||||
setShowDemoModal(true);
|
||||
} else {
|
||||
handleDelete(recipe.id);
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -30,12 +37,19 @@ function CookbookRecipeTile({ recipe, handleDelete }: CookbookRecipeTileProps) {
|
|||
</button>
|
||||
</div>
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
isOpen={showConfirmModal}
|
||||
onClose={closeModal}
|
||||
message="Are you sure you want to delete this recipe?"
|
||||
confirmAction={confirmDelete}
|
||||
cancelAction={closeModal}
|
||||
/>
|
||||
{showDemoModal && (
|
||||
<DemoModal
|
||||
isOpen={showDemoModal}
|
||||
onClose={() => setShowDemoModal(false)}
|
||||
closeModal={() => setShowDemoModal(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
28
frontend/src/components/DemoModal.tsx
Normal file
28
frontend/src/components/DemoModal.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface DemoModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const DemoModal = ({ isOpen, onClose, closeModal }: DemoModalProps) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="modal-overlay fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 flex justify-center items-center" onClick={onClose}>
|
||||
<div className="modal-content bg-amber-200 p-12 rounded-md shadow-md" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="modal-msg">
|
||||
<p>Thanks for checking out my app! Database write operations are disabled in demo mode.</p>
|
||||
<p><a className="text-blue-600" href="mailto:access@fredzernia.com">access@fredzernia.com</a> to request access to the production build</p>
|
||||
<p>Find out more about this app <Link to={'/about'} className="text-blue-600">here</Link></p>
|
||||
</div>
|
||||
<div className="modal-buttons">
|
||||
<button className="bg-amber-600 rounded-md m-4 pt-1 pb-1 pr-2 pl-2" onClick={closeModal}>OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DemoModal;
|
|
@ -4,6 +4,7 @@ import { useNavigate } from "react-router-dom";
|
|||
import AddBulkIngredients from "../components/AddBulkIngredients.tsx"
|
||||
import AddBulkSteps from "../components/AddBulkSteps.tsx"
|
||||
import StarRating from "../components/StarRating.tsx"
|
||||
import DemoModal from '../components/DemoModal.tsx'
|
||||
// import { type Step } from "../types/Recipe";
|
||||
|
||||
interface Step {
|
||||
|
@ -23,9 +24,14 @@ function AddRecipe() {
|
|||
const [stars, setStars] = useState(0);
|
||||
const [prepMinutes, setPrepMinutes] = useState(5);
|
||||
const [cookMinutes, setCookMinutes] = useState(5);
|
||||
const [showDemoModal, setShowDemoModal] = useState(false);
|
||||
|
||||
const addRecipeForm = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (process.env.NODE_ENV === 'demo') {
|
||||
setShowDemoModal(true);
|
||||
return;
|
||||
}
|
||||
const stepsHash = Object.fromEntries(
|
||||
steps.map(step => [step.step_number, step.instruction])
|
||||
);
|
||||
|
@ -139,6 +145,13 @@ function AddRecipe() {
|
|||
submit
|
||||
</button>
|
||||
</form>
|
||||
{showDemoModal && (
|
||||
<DemoModal
|
||||
isOpen={showDemoModal}
|
||||
onClose={() => setShowDemoModal(false)}
|
||||
closeModal={() => setShowDemoModal(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const baseUrl = process.env.NODE_ENV === 'production'
|
||||
const baseUrl = process.env.NODE_ENV !== 'dev'
|
||||
? '/'
|
||||
: 'http://localhost:3000/';
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import react from "@vitejs/plugin-react";
|
|||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: "ec683cee72d30c5030.fredzernia.com",
|
||||
allowedHosts: ["ec683cee72d30c5030.fredzernia.com"],
|
||||
allowedHosts: ["recipe-prod.fredzernia.com", "recipe-demo.fredzernia.com"],
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue