diff --git a/package-lock.json b/package-lock.json index 81548ad..f3e7a22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "tailwindcss-animate": "^1.0.7" }, "devDependencies": { + "@types/bun": "^1.1.13", "@types/node": "^20.17.6", "@types/pg": "^8.11.10", "@types/react": "^18", @@ -2911,6 +2912,15 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@types/bun": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.1.13.tgz", + "integrity": "sha512-KmQxSBgVWCl6RSuerlLGZlIWfdxkKqat0nxN61+qu4y1KDn0Ll3j7v1Pl8GnaL3a/U6GGWVTJh75ap62kR1E8Q==", + "dev": true, + "dependencies": { + "bun-types": "1.1.34" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -3030,6 +3040,15 @@ "@types/react": "*" } }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "devOptional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz", @@ -4512,6 +4531,31 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bun-types": { + "version": "1.1.34", + "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.1.34.tgz", + "integrity": "sha512-br5QygTEL/TwB4uQOb96Ky22j4Gq2WxWH/8Oqv20fk5HagwKXo/akB+LiYgSfzexCt6kkcUaVm+bKiPl71xPvw==", + "devOptional": true, + "dependencies": { + "@types/node": "~20.12.8", + "@types/ws": "~8.5.10" + } + }, + "node_modules/bun-types/node_modules/@types/node": { + "version": "20.12.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.14.tgz", + "integrity": "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==", + "devOptional": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/bun-types/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "devOptional": true + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", diff --git a/src/actions/brandActions.ts b/src/actions/brandActions.ts index 65c052c..2284c87 100644 --- a/src/actions/brandActions.ts +++ b/src/actions/brandActions.ts @@ -2,7 +2,7 @@ import { eq, not , asc} from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { db } from "../db"; -import { brand } from "../db/schema/Brand"; +import { brand } from "@db/schema/Brand"; export const getData = async () => { const data = await db.select().from(brand).orderBy(asc(brand.name)); return data; diff --git a/src/actions/componentTypeActions.ts b/src/actions/componentTypeActions.ts new file mode 100644 index 0000000..b808f09 --- /dev/null +++ b/src/actions/componentTypeActions.ts @@ -0,0 +1,10 @@ +"use server"; +import { eq, not , asc} from "drizzle-orm"; +import { revalidatePath } from "next/cache"; +import { db } from "../db"; +import { ComponentType } from "@db/schema/ComponentTypes"; +export const getData = async () => { + const data = await db.select().from(ComponentType).orderBy(asc(ComponentType.name)); + return data; +}; + diff --git a/src/actions/manufacturerActions.ts b/src/actions/manufacturerActions.ts index 53f30dc..e16fbfe 100644 --- a/src/actions/manufacturerActions.ts +++ b/src/actions/manufacturerActions.ts @@ -2,7 +2,7 @@ import { eq, not , asc} from "drizzle-orm"; import { revalidatePath } from "next/cache"; import { db } from "../db"; -import { manufacturer } from "@/db/schema/Manufacturer"; +import { manufacturer } from "@db/schema/Manufacturer"; export const getData = async () => { const data = await db.select().from(manufacturer).orderBy(asc(manufacturer.name)); return data; diff --git a/src/app/Accounts/page.tsx b/src/app/Accounts/page.tsx index bf623dc..c7ce191 100644 --- a/src/app/Accounts/page.tsx +++ b/src/app/Accounts/page.tsx @@ -1,6 +1,5 @@ -import { Account } from "@/db/schema/Account"; +import { Account } from "@db/schema/Account"; import { getData } from "../../actions/accountActions"; -import Brands from "../../components/Brand/BrandsList"; export default async function AccountsPage() { const data = await getData(); diff --git a/src/app/page.tsx b/src/app/page.tsx index 1212734..43f9382 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,7 @@ -import About from "../components/About"; -import Contact from "../components/Contact"; +import About from "../components/site/About"; +import Contact from "../components/site/Contact"; import FeaturesSection from "../components/FeaturesSection"; -import Footer from "../components/Footer "; +import Footer from "../components/site/Footer "; import Header from "../components/Header"; import Hero from "../components/Hero"; diff --git a/src/components/ComponentType/ComponentTypeList.tsx b/src/components/ComponentType/ComponentTypeList.tsx new file mode 100644 index 0000000..b121372 --- /dev/null +++ b/src/components/ComponentType/ComponentTypeList.tsx @@ -0,0 +1,57 @@ +"use client"; +import { FC, useState } from "react"; +import { componentTypeType } from "src/types/componentTypeType"; +import { componentType } from './componentType' +// import AddBrand from "./addBrand"; +import { getData } from "../../actions/componentTypeActions"; + +interface Props { + componentType: componentType[]; +} + +const ComponentTypeList: FC = ({ componentType }) => { + // State to manage the list of brand items + const [brandItems, setBrandItems] = useState(brands); + + // Function to create a new brand 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 brand 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 deleteBrandItem = (id: number) => { + setBrandItems((prev) => prev.filter((brand) => brand.id !== id)); + deleteBrand(id); + }; + + // Rendering the brand List component + return ( +
+
Ballistic Builder Brand
+
+ {/* Mapping through brand items and rendering brand component for each */} + {brandItems.map((brand) => ( + + ))} +
+ {/* Adding brand component for creating new brand */} + +
+ ); +}; +export default ComponentTypeList; \ No newline at end of file diff --git a/src/components/ComponentType/componentType.tsx b/src/components/ComponentType/componentType.tsx new file mode 100644 index 0000000..e71762e --- /dev/null +++ b/src/components/ComponentType/componentType.tsx @@ -0,0 +1,99 @@ +"use client"; +import { ChangeEvent, FC, useState } from "react"; +import { componentTypeType } from "src/types/componentTypeType"; + +interface Props { + componentType: componentTypeType; + changeComponentTypeName: (id: number, name: string) => void; + + deleteComponentType: (id: number) => void; +} + +export const componentType: FC = ({ + componentType, + changeComponentTypeName, + deleteComponentType, +}) => { + // State for handling editing mode + const [editing, setEditing] = useState(false); + + // State for handling text input + const [name, setName] = useState( componentType.name); + + // Event handler for text input change + const handleNameChange = (e: ChangeEvent) => { + 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 () => { + changeComponentTypeName(componentType.id, name); + setEditing(false); + }; + + // Event handler for canceling the edit mode + const handleCancel = () => { + setEditing(false); + setName(componentType.name); + }; + // Event handler for deleting a componentType item + const handleDelete = () => { + if (confirm("Are you sure you want to delete this brand?")) { + deleteComponentType(componentType.id); + } + }; + // Rendering the Brands component + return ( +
+ {/* Checkbox for marking the componentType as done */} + + {/* Input field for brand text */} + + {/* Action buttons for editing, saving, canceling, and deleting */} +
+ {editing ? ( + + ) : ( + + )} + {editing ? ( + + ) : ( + + )} +
+
+ ); +}; +export default componentType; \ No newline at end of file diff --git a/src/components/DropList/statesDroplist.tsx b/src/components/DropList/statesDroplist.tsx new file mode 100644 index 0000000..da86a7a --- /dev/null +++ b/src/components/DropList/statesDroplist.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select, { SelectChangeEvent } from '@mui/material/Select'; + +export default function BasicSelect() { + const [abbrev, setAbbrev] = React.useState(''); + + const handleChange = (event: SelectChangeEvent) => { + setAbbrev(event.target.value as string); + }; + + return ( + + + State + + + + ); +} \ No newline at end of file diff --git a/src/components/HomeContent/index.tsx b/src/components/HomeContent/index.tsx index 100a0a9..82f78b7 100644 --- a/src/components/HomeContent/index.tsx +++ b/src/components/HomeContent/index.tsx @@ -2,9 +2,9 @@ import Link from "next/link"; import Header from "../Header"; import Hero from "../Hero"; import FeaturesSection from "../FeaturesSection"; -import About from "../About"; -import Contact from "../Contact"; -import Footer from "../Footer "; +import About from "../site/About"; +import Contact from "../site/Contact"; +import Footer from "../site/Footer "; export default function HomeContent() { diff --git a/src/components/About/index.tsx b/src/components/site/About/index.tsx similarity index 100% rename from src/components/About/index.tsx rename to src/components/site/About/index.tsx diff --git a/src/components/Contact/index.tsx b/src/components/site/Contact/index.tsx similarity index 100% rename from src/components/Contact/index.tsx rename to src/components/site/Contact/index.tsx diff --git a/src/components/Footer /index.tsx b/src/components/site/Footer /index.tsx similarity index 100% rename from src/components/Footer /index.tsx rename to src/components/site/Footer /index.tsx diff --git a/src/db/index.ts b/src/db/index.ts index c2226e6..72643cf 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -3,11 +3,12 @@ import { drizzle } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; import { sql } from 'drizzle-orm'; + // db/index.ts const pool = new Pool({ connectionString: process.env.DATABASE_URL, }); -export const db = drizzle(pool); +export const db = drizzle(pool, {logger : true}); diff --git a/src/db/schema/States.ts b/src/db/schema/States.ts new file mode 100644 index 0000000..4f63e74 --- /dev/null +++ b/src/db/schema/States.ts @@ -0,0 +1,7 @@ +import { integer, varchar, pgTable } from "drizzle-orm/pg-core"; + +export const states = pgTable("states", { + id: integer().primaryKey().generatedByDefaultAsIdentity({ name: "states_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + state: varchar({ length: 50 }), + abbreviation: varchar({ length: 50 }), +}); \ No newline at end of file diff --git a/src/drizzle/relations.ts b/src/drizzle/relations.ts new file mode 100644 index 0000000..80768e2 --- /dev/null +++ b/src/drizzle/relations.ts @@ -0,0 +1,3 @@ +import { relations } from "drizzle-orm/relations"; +import { } from "./schema"; + diff --git a/src/drizzle/schema.ts b/src/drizzle/schema.ts new file mode 100644 index 0000000..e42766d --- /dev/null +++ b/src/drizzle/schema.ts @@ -0,0 +1,203 @@ +import { pgTable, integer, varchar, timestamp, text, numeric, unique, doublePrecision } from "drizzle-orm/pg-core" +import { sql } from "drizzle-orm" + + + +export const productFeeds = pgTable("product_feeds", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "productfeeds_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + resellerId: integer("reseller_id").notNull(), + feedUrl: varchar("feed_url", { length: 255 }).notNull(), + lastUpdate: timestamp("last_update", { mode: 'string' }), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const products = pgTable("products", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "products_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 255 }).notNull(), + description: text().notNull(), + price: numeric().notNull(), + resellerId: integer("reseller_id").notNull(), + categoryId: integer("category_id").notNull(), + stockQty: integer("stock_qty").default(0), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const categories = pgTable("categories", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "categories_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 100 }).notNull(), + parentCategoryId: integer("parent_category_id"), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const brands = pgTable("brands", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "brands_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 100 }).notNull(), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const manufacturer = pgTable("manufacturer", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "manufacturer_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 100 }).notNull(), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const baseTable = pgTable("base_table", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "base_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const componentType = pgTable("component_type", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "component_type_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 100 }).notNull(), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const states = pgTable("states", { + id: integer().primaryKey().generatedByDefaultAsIdentity({ name: "states_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + state: varchar({ length: 50 }), + abbreviation: varchar({ length: 50 }), +}); + +export const balAccounts = pgTable("bal_accounts", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "accountsid_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + firstName: varchar("first_name", { length: 40 }), + lastName: varchar("last_name", { length: 40 }), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), + email: varchar({ length: 100 }), + username: varchar({ length: 50 }).notNull(), + passwordHash: varchar("password_hash", { length: 255 }).notNull(), +}, (table) => { + return { + balAccountsUsernameUnique: unique("bal_accounts_username_unique").on(table.username), + balAccountsPasswordHashUnique: unique("bal_accounts_password_hash_unique").on(table.passwordHash), + } +}); + +export const builds = pgTable("builds", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + accountId: integer("account_id").notNull(), + name: varchar({ length: 255 }).notNull(), + description: text(), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const buildsComponents = pgTable("builds_components", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "build_components_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + buildId: integer("build_id").notNull(), + productId: integer("product_id").notNull(), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const lipseycatalog = pgTable("lipseycatalog", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "lipseycatalog_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + itemno: varchar({ length: 20 }).notNull(), + description1: text(), + description2: text(), + upc: varchar({ length: 20 }), + manufacturermodelno: varchar({ length: 30 }), + msrp: doublePrecision(), + model: text(), + calibergauge: text(), + manufacturer: text(), + type: text(), + action: text(), + barrellength: text(), + capacity: text(), + finish: text(), + overalllength: text(), + receiver: text(), + safety: text(), + sights: text(), + stockframegrips: text(), + magazine: text(), + weight: text(), + imagename: text(), + chamber: text(), + drilledandtapped: text(), + rateoftwist: text(), + itemtype: text(), + additionalfeature1: text(), + additionalfeature2: text(), + additionalfeature3: text(), + shippingweight: text(), + boundbookmanufacturer: text(), + boundbookmodel: text(), + boundbooktype: text(), + nfathreadpattern: text(), + nfaattachmentmethod: text(), + nfabaffletype: text(), + silencercanbedisassembled: text(), + silencerconstructionmaterial: text(), + nfadbreduction: text(), + silenceroutsidediameter: text(), + nfaform3Caliber: text(), + opticmagnification: text(), + maintubesize: text(), + adjustableobjective: text(), + objectivesize: text(), + opticadjustments: text(), + illuminatedreticle: text(), + reticle: text(), + exclusive: text(), + quantity: varchar({ length: 10 }).default(sql`NULL`), + allocated: text(), + onsale: text(), + price: doublePrecision(), + currentprice: doublePrecision(), + retailmap: doublePrecision(), + fflrequired: text(), + sotrequired: text(), + exclusivetype: text(), + scopecoverincluded: text(), + special: text(), + sightstype: text(), + case: text(), + choke: text(), + dbreduction: text(), + family: text(), + finishtype: text(), + frame: text(), + griptype: varchar({ length: 30 }), + handgunslidematerial: text(), + countryoforigin: varchar({ length: 4 }), + itemlength: text(), + itemwidth: text(), + itemheight: text(), + packagelength: doublePrecision(), + packagewidth: doublePrecision(), + packageheight: doublePrecision(), + itemgroup: varchar({ length: 40 }), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); + +export const balResellers = pgTable("bal_resellers", { + id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "resellers_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }), + name: varchar({ length: 100 }).notNull(), + websiteUrl: varchar("website_url", { length: 255 }), + contactEmail: varchar("contact_email", { length: 100 }), + updatedAt: timestamp("updated_at", { mode: 'string' }).defaultNow().notNull(), + createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(), + deletedAt: timestamp("deleted_at", { mode: 'string' }), +}); diff --git a/src/types/componentTypeType.ts b/src/types/componentTypeType.ts new file mode 100644 index 0000000..4ffc9a9 --- /dev/null +++ b/src/types/componentTypeType.ts @@ -0,0 +1,5 @@ +//field is named componentType +export type componentTypeType = { + id: number; + name: string; + }; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index dcc5fc7..ce97542 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,21 +20,29 @@ } ], "paths": { - "@/*": [ - "./src/*"], + "@src/*": [ + "/src/*"], "@/db/*": [ "./src/db/*"], - "components/*": [ - "/src/app/components/*" + "@db/*": [ + "./src/db/*"], + "@types/*": [ + "/src/types/*"], + "@components/*": [ + "/src/components/*", + "/src/components/Brands/*" ], - "layouts/*": [ - "/src/app/components/layouts/*" + "@actions/*": [ + "/src/actions/*" ], - "fragments/*": [ + "@layouts/*": [ + "/src/components/layouts/*" + ], + "@fragments/*": [ "/src/app/Fragments/*" ], - "lib/*": [ - "/src/app/lib/*" + "@lib/*": [ + "/src/lib/*" ], "scss/*": [ "./src/scss/*"