mirror of
https://gitea.gofwd.group/dstrawsb/ballistic-builder.git
synced 2025-12-06 02:36:44 -05:00
added brands
This commit is contained in:
27
src/actions/brandActions.ts
Normal file
27
src/actions/brandActions.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
"use server";
|
||||||
|
import { eq, not } from "drizzle-orm";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { db } from "../db";
|
||||||
|
import { brand } from "../db/schema/Brand";
|
||||||
|
export const getData = async () => {
|
||||||
|
const data = await db.select().from(brand);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
export const addBrand = async ( name: string) => {
|
||||||
|
await db.insert(brand).values({
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const deleteBrand = async (id: number) => {
|
||||||
|
await db.delete(brand).where(eq(brand.id, id));
|
||||||
|
revalidatePath("/");
|
||||||
|
};
|
||||||
|
export const editBrand = async (id: number, name: string) => {
|
||||||
|
await db
|
||||||
|
.update(brand)
|
||||||
|
.set({
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
.where(eq(brand.id, id));
|
||||||
|
revalidatePath("/");
|
||||||
|
};
|
||||||
@@ -5,8 +5,11 @@ import Hero from "../components/Hero";
|
|||||||
import Contact from "../components/Contact";
|
import Contact from "../components/Contact";
|
||||||
import Footer from "../components/Footer ";
|
import Footer from "../components/Footer ";
|
||||||
import { ChakraProvider } from "@chakra-ui/react";
|
import { ChakraProvider } from "@chakra-ui/react";
|
||||||
|
import { getData } from "../actions/brandActions";
|
||||||
|
import Brands from "../components/Brand/brands";
|
||||||
|
|
||||||
export default function Home() {
|
export default async function Home() {
|
||||||
|
const data = await getData();
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-100 min-h-screen flex flex-col">
|
<div className="bg-gray-100 min-h-screen flex flex-col">
|
||||||
<Header />
|
<Header />
|
||||||
@@ -15,7 +18,7 @@ export default function Home() {
|
|||||||
<About />
|
<About />
|
||||||
<Contact />
|
<Contact />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
<Brands brands={data} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
38
src/components/Brand/addBrand.tsx
Normal file
38
src/components/Brand/addBrand.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"use client";
|
||||||
|
import { ChangeEvent, FC, useState } from "react";
|
||||||
|
interface Props {
|
||||||
|
createBrand: (value: string) => void;
|
||||||
|
}
|
||||||
|
const AddBrand: FC<Props> = ({ createBrand }) => {
|
||||||
|
// State for handling input value
|
||||||
|
const [input, setInput] = useState("");
|
||||||
|
// Event handler for input change
|
||||||
|
const handleInput = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setInput(e.target.value);
|
||||||
|
};
|
||||||
|
// Event handler for adding a new brand
|
||||||
|
const handleAdd = async () => {
|
||||||
|
createBrand(input);
|
||||||
|
setInput("");
|
||||||
|
};
|
||||||
|
// Rendering the AddBrand component
|
||||||
|
return (
|
||||||
|
<div className="w-full flex gap-1 mt-2">
|
||||||
|
{/* Input field for entering new brand text */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="w-full px-2 py-1 border border-gray-200 rounded outline-none"
|
||||||
|
onChange={handleInput}
|
||||||
|
value={input}
|
||||||
|
/>
|
||||||
|
{/* Button for adding a new brand */}
|
||||||
|
<button
|
||||||
|
className="flex items-center justify-center bg-green-600 text-green-50 rounded px-2 h-9 w-14 py-1"
|
||||||
|
onClick={handleAdd}
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default AddBrand;
|
||||||
92
src/components/Brand/brand.tsx
Normal file
92
src/components/Brand/brand.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
"use client";
|
||||||
|
import { ChangeEvent, FC, useState } from "react";
|
||||||
|
import { brandType } from "../../types/brandType";
|
||||||
|
interface Props {
|
||||||
|
brand: brandType;
|
||||||
|
changeBrandName: (id: number, name: string) => void;
|
||||||
|
|
||||||
|
deleteBrand: (id: number) => void;
|
||||||
|
}
|
||||||
|
const Brand: FC<Props> = ({
|
||||||
|
brand,
|
||||||
|
changeBrandName,
|
||||||
|
deleteBrand,
|
||||||
|
}) => {
|
||||||
|
// State for handling editing mode
|
||||||
|
const [editing, setEditing] = useState(false);
|
||||||
|
// State for handling text input
|
||||||
|
const [name, setName] = useState(brand.name);
|
||||||
|
// Event handler for text input change
|
||||||
|
const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setName(e.target.value);
|
||||||
|
};
|
||||||
|
// Event handler for initiating the edit mode
|
||||||
|
const handleEdit = () => {
|
||||||
|
setEditing(true);
|
||||||
|
};
|
||||||
|
// Event handler for saving the edited text
|
||||||
|
const handleSave = async () => {
|
||||||
|
changeBrandName(brand.id, name);
|
||||||
|
setEditing(false);
|
||||||
|
};
|
||||||
|
// Event handler for canceling the edit mode
|
||||||
|
const handleCancel = () => {
|
||||||
|
setEditing(false);
|
||||||
|
setName(brand.name);
|
||||||
|
};
|
||||||
|
// Event handler for deleting a todo item
|
||||||
|
const handleDelete = () => {
|
||||||
|
if (confirm("Are you sure you want to delete this brand?")) {
|
||||||
|
deleteBrand(brand.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Rendering the Todo component
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 p-4 border-gray-200 border-solid border rounded-lg">
|
||||||
|
{/* Checkbox for marking the todo as done */}
|
||||||
|
|
||||||
|
{/* Input field for brand text */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={name}
|
||||||
|
onChange={handleNameChange}
|
||||||
|
readOnly={!editing}
|
||||||
|
className="outline-none read-only:border-transparent focus:border border-gray-200 rounded px-2 py-1 w-full"
|
||||||
|
/>
|
||||||
|
{/* Action buttons for editing, saving, canceling, and deleting */}
|
||||||
|
<div className="flex gap-1 ml-auto">
|
||||||
|
{editing ? (
|
||||||
|
<button
|
||||||
|
onClick={handleSave}
|
||||||
|
className="bg-green-600 text-green-50 rounded px-2 w-14 py-1"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={handleEdit}
|
||||||
|
className="bg-blue-400 text-blue-50 rounded w-14 px-2 py-1"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{editing ? (
|
||||||
|
<button
|
||||||
|
onClick={handleCancel}
|
||||||
|
className="bg-red-400 w-16 text-red-50 rounded px-2 py-1"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={handleDelete}
|
||||||
|
className="bg-red-400 w-16 text-red-50 rounded px-2 py-1"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Brand;
|
||||||
52
src/components/Brand/brands.tsx
Normal file
52
src/components/Brand/brands.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
"use client";
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import { brandType } from "../../types/brandType";
|
||||||
|
import Brand from "./brand";
|
||||||
|
import AddBrand from "./addBrand";
|
||||||
|
import { addBrand, deleteBrand, editBrand } from "../../actions/brandActions";
|
||||||
|
interface Props {
|
||||||
|
brands: brandType[];
|
||||||
|
}
|
||||||
|
const Brands: FC<Props> = ({ brands }) => {
|
||||||
|
// State to manage the list of todo items
|
||||||
|
const [brandItems, setBrandItems] = useState<brandType[]>(brands);
|
||||||
|
// Function to create a new todo item
|
||||||
|
const createBrand = (name: string) => {
|
||||||
|
const id = (brandItems.at(-1)?.id || 0) + 1;
|
||||||
|
addBrand(name);
|
||||||
|
setBrandItems((prev) => [...prev, { id: id, name: name }]);
|
||||||
|
};
|
||||||
|
// Function to change the text of a todo item
|
||||||
|
const changeBrandName = (id: number, name: string) => {
|
||||||
|
setBrandItems((prev) =>
|
||||||
|
prev.map((brand) => (brand.id === id ? { ...brand, name } : brand))
|
||||||
|
);
|
||||||
|
editBrand(id, name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to delete a brand item
|
||||||
|
const deleteTodoItem = (id: number) => {
|
||||||
|
setBrandItems((prev) => prev.filter((brand) => brand.id !== id));
|
||||||
|
deleteBrand(id);
|
||||||
|
};
|
||||||
|
// Rendering the brand List component
|
||||||
|
return (
|
||||||
|
<main className="flex mx-auto max-w-xl w-full min-h-screen flex-col items-center p-16">
|
||||||
|
<div className="text-5xl font-medium">To-do app</div>
|
||||||
|
<div className="w-full flex flex-col mt-8 gap-2">
|
||||||
|
{/* Mapping through todoItems and rendering Todo component for each */}
|
||||||
|
{brandItems.map((brand) => (
|
||||||
|
<Brand
|
||||||
|
key={brand.id}
|
||||||
|
brand={brand}
|
||||||
|
changeBrandName={changeBrandName}
|
||||||
|
deleteBrand={deleteBrand}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{/* Adding Todo component for creating new todos */}
|
||||||
|
<AddBrand createBrand={createBrand} />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Brands;
|
||||||
4
src/types/brandType.ts
Normal file
4
src/types/brandType.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export type brandType = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
@@ -20,8 +20,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"],
|
"@/*": [
|
||||||
|
"./src/*"],
|
||||||
|
"@/db/*": [
|
||||||
|
"./src/db/*"],
|
||||||
"components/*": [
|
"components/*": [
|
||||||
"/src/app/components/*"
|
"/src/app/components/*"
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user