profanity filter

This commit is contained in:
fred 2025-08-20 12:04:58 -07:00
parent 2e7d9e6ba6
commit 798e879863
2 changed files with 83 additions and 22 deletions

View file

@ -1,11 +1,12 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { addRecipe } from "../services/frontendApi.js";
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 '../css/colorTheme.css';
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 "../css/colorTheme.css";
import { isProfane } from "../utils/profanityFilter";
interface Step {
step_number: number;
@ -28,14 +29,29 @@ function AddRecipe() {
const addRecipeForm = async (event: React.FormEvent) => {
event.preventDefault();
if (process.env.NODE_ENV === 'demo') {
if (
isProfane(recipeName) ||
isProfane(recipeCuisine) ||
ingredients.some((ingredient) => isProfane(ingredient)) ||
steps.some((step) => isProfane(step.instruction)) ||
isProfane(author)
) {
alert("Your submission contains inappropriate language.");
return;
}
if (process.env.NODE_ENV === "demo") {
setShowDemoModal(true);
return;
}
const stepsHash = Object.fromEntries(
steps.map(step => [step.step_number, step.instruction])
steps.map((step) => [step.step_number, step.instruction]),
);
if (recipeName && recipeCuisine && Object.keys(stepsHash).length > 0 && ingredients.length > 0) {
if (
recipeName &&
recipeCuisine &&
Object.keys(stepsHash).length > 0 &&
ingredients.length > 0
) {
const recipeData = {
name: recipeName,
cuisine: recipeCuisine.toLowerCase(),
@ -44,13 +60,13 @@ function AddRecipe() {
cook_minutes: cookMinutes,
stars: stars,
ingredients: ingredients,
steps: stepsHash
}
console.log(recipeData)
steps: stepsHash,
};
console.log(recipeData);
const data = await addRecipe(recipeData);
setNewRecipeId(data.id);
} else {
alert('missing required data')
alert("missing required data");
}
};
@ -88,7 +104,12 @@ function AddRecipe() {
/>
<div className="flex items-center justify-between mb-4">
<div>
<label htmlFor="prepTime" className="mr-2 font-bold text-[var(--color-secondaryTextDark)]">Prep Time:</label>
<label
htmlFor="prepTime"
className="mr-2 font-bold text-[var(--color-secondaryTextDark)]"
>
Prep Time:
</label>
<input
type="number"
placeholder="prep time in minutes"
@ -96,10 +117,17 @@ function AddRecipe() {
value={prepMinutes}
onChange={(e) => setPrepMinutes(parseInt(e.target.value))}
/>
<span className="ml-2 text-[var(--color-secondaryTextDark)]">minutes</span>
<span className="ml-2 text-[var(--color-secondaryTextDark)]">
minutes
</span>
</div>
<div>
<label htmlFor="cookTime" className="mr-2 font-bold text-[var(--color-secondaryTextDark)]">Cook Time:</label>
<label
htmlFor="cookTime"
className="mr-2 font-bold text-[var(--color-secondaryTextDark)]"
>
Cook Time:
</label>
<input
type="number"
placeholder="cook time in minutes"
@ -107,10 +135,15 @@ function AddRecipe() {
value={cookMinutes}
onChange={(e) => setCookMinutes(parseInt(e.target.value))}
/>
<span className="ml-2 text-[var(--color-secondaryTextDark)]">minutes</span>
<span className="ml-2 text-[var(--color-secondaryTextDark)]">
minutes
</span>
</div>
<div>
<StarRating rating={stars} onRatingChange={(newRating: number) => setStars(newRating)} />
<StarRating
rating={stars}
onRatingChange={(newRating: number) => setStars(newRating)}
/>
</div>
</div>
<label className="mb-4 flex items-center cursor-pointer">
@ -124,7 +157,10 @@ function AddRecipe() {
</div>
</label>
<div>
<AddBulkIngredients ingredients={ingredients} onChange={setIngredients} />
<AddBulkIngredients
ingredients={ingredients}
onChange={setIngredients}
/>
</div>
{/*<ul className="mb-4">
{ingredients.map((ing, index) => (
@ -143,7 +179,10 @@ function AddRecipe() {
</li>
))}
</ul>*/}
<button type="submit" className="ar-button bg-[var(--color-buttonBg)] text-[var(--color-textLight)] py-2 px-4 rounded hover:bg-[var(--color-buttonBgHover)]">
<button
type="submit"
className="ar-button bg-[var(--color-buttonBg)] text-[var(--color-textLight)] py-2 px-4 rounded hover:bg-[var(--color-buttonBgHover)]"
>
submit
</button>
</form>
@ -155,6 +194,6 @@ function AddRecipe() {
/>
)}
</div>
)
);
}
export default AddRecipe
export default AddRecipe;

View file

@ -0,0 +1,22 @@
let profaneWords: string[] = [];
const loadProfaneWords = async () => {
try {
const response = await fetch(
"https://raw.githubusercontent.com/web-mech/badwords/master/lib/lang.json",
);
const data = await response.json();
profaneWords = data.words;
} catch (error) {
if (process.env.NODE_ENV === "dev") {
console.log("Error loading profane words:", (error as Error).message);
}
}
};
loadProfaneWords();
export const isProfane = (input: string): boolean => {
const words = input.toLowerCase().split(/\s+/);
return words.some((word) => profaneWords.includes(word));
};