accounts table and many other fixes

This commit is contained in:
2025-01-19 23:49:48 -05:00
parent 26ae83faac
commit e0688a1406
22 changed files with 208 additions and 43 deletions

View File

@@ -3,9 +3,18 @@ import { eq, not , asc} from "drizzle-orm";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
import { db } from "@db/index"; import { db } from "@db/index";
import { accounts } from "@schemas/schema"; import { accounts } from "@schemas/schema";
import { vw_accounts } from "@schemas/schema";
export const getData = async () => { export const getData = async () => {
const data = await db.select().from(accounts).orderBy(asc(accounts.last_name)); const data = await db.select().from(accounts).orderBy(asc(accounts.userId));
return data;
};
export const getAllAccounts = async () => {
return getData();
};
export const getViewAccounts = async () => {
const data = await db.select().from(vw_accounts).orderBy(asc(vw_accounts.last_name));
return data; return data;
}; };

View File

@@ -3,8 +3,12 @@ import { eq, not , asc} from "drizzle-orm";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
import { db } from "../db"; import { db } from "../db";
import { componentType } from "@schemas/schema"; import { componentType } from "@schemas/schema";
export const getData = async () => { export const getData = async () => {
const data = await db.select().from(componentType).orderBy(asc(componentType.name)); const data = await db.select().from(componentType).orderBy(asc(componentType.name));
return data; return data;
}; };
export const getComponentTypeName = async () => {
return getData();
};

View File

@@ -10,3 +10,6 @@ export const getData = async () => {
return data; return data;
}; };
export const getManufacturersName = async () => {
return getData();
};

View File

@@ -8,7 +8,7 @@ export const getData = async () => {
const data = await db.select().from(users).orderBy(asc(users.last_name)); const data = await db.select().from(users).orderBy(asc(users.last_name));
return data; return data;
}; };
export const getAllUsers = async () => { export const getAllUsersOrdrByLastname = async () => {
const data = await db.select().from(users).orderBy(asc(users.last_name)); const data = await db.select().from(users).orderBy(asc(users.last_name));
return data; return data;
}; };

View File

@@ -13,7 +13,6 @@ export default function Blog() {
and exploring firearm parts. Designed for enthusiasts by and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible. enthusiasts, we make firearm building easy and accessible.
</p> </p>
</div> </div>
</section> </section>
) )

View File

@@ -13,7 +13,6 @@ export default function Disclosure() {
and exploring firearm parts. Designed for enthusiasts by and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible. enthusiasts, we make firearm building easy and accessible.
</p> </p>
</div> </div>
</section> </section>
) )

View File

@@ -8,7 +8,6 @@ export default function Footer() {
<div className="container mx-auto px-6 text-center"> <div className="container mx-auto px-6 text-center">
<p>&copy; {new Date().getFullYear()} {constants.APP_NAME}. All rights reserved.</p> <p>&copy; {new Date().getFullYear()} {constants.APP_NAME}. All rights reserved.</p>
<p>Built by Forward Group </p> <p>Built by Forward Group </p>
</div> </div>
</footer> </footer>
) )

View File

@@ -13,7 +13,6 @@ export default function Jobs() {
and exploring firearm parts. Designed for enthusiasts by and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible. enthusiasts, we make firearm building easy and accessible.
</p> </p>
</div> </div>
</section> </section>
) )

View File

@@ -13,7 +13,6 @@ export default function About() {
and exploring firearm parts. Designed for enthusiasts by and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible. enthusiasts, we make firearm building easy and accessible.
</p> </p>
</div> </div>
</section> </section>
) )

View File

@@ -13,7 +13,6 @@ export default function TOS() {
and exploring firearm parts. Designed for enthusiasts by and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible. enthusiasts, we make firearm building easy and accessible.
</p> </p>
</div> </div>
</section> </section>
) )

View File

@@ -1,19 +1,29 @@
import { accounts } from "@schemas/schema"; import { accounts } from "@schemas/schema";
import { getData } from "@actions/accountActions"; import { getViewAccounts } from "@actions/accountActions";
import Account from "@components/Account"; // Adjust the import path as necessary import AccountsTable from "@src/components/AccountsTable"; // Adjust the import path as necessary
import React from 'react'; import React, { Suspense } from 'react';
import { ColumnHeadings } from "@src/lib/utils";
import PageHero from "@src/components/PageHero";
export interface AccountProps {
account: any; // Adjust the type according to your data structure
}
export default async function AccountsPage() { export default async function AccountsPage() {
const data = await getData(); const columnHeadings = new ColumnHeadings([
"First Name",
"Last Name",
"Actions",
]);
const data = await getViewAccounts();
return ( return (
<div className="bg-gray-100 min-h-screen flex flex-col"> <div>
<Account account={data} /> <PageHero title="Accounts" />
<div className="container mx-auto">
<Suspense fallback="Loading...">
<AccountsTable data={data} newColumnHeadings={columnHeadings}></AccountsTable>
</Suspense>
</div>
</div> </div>
); );
} }

View File

@@ -10,7 +10,7 @@ export default async function UsersPage() {
const data = await getData(); const data = await getData();
const columnHeadings = new ColumnHeadings(['E-mail Address', 'First Name', 'Last Name', 'Blank']); const columnHeadings = new ColumnHeadings(['E-mail Address', 'First Name', 'Last Name', 'User Name']);
return ( return (
<div> <div>
<PageHero title="Users" /> <PageHero title="Users" />

View File

@@ -0,0 +1,18 @@
import { getOptics } from "@queries/PSA";
import partTypes from 'src/data/parts_cats.json';
import styles from '../styles.module.css';
import PageHero from "@components/PageHero";
import SortTable from "@components/SortTable";
export default async function OpticsPage() {
const psa = await getOptics();
return (
<div>
<PageHero title="Optics" />
<div className="container mx-auto">
<SortTable data={psa}></SortTable>
</div>
</div>
);
}

View File

@@ -1,14 +0,0 @@
import { AccountProps } from "@src/app/Accounts/page";
import React from "react";
export const Account: React.FC<AccountProps> = ({ account }) => {
return (
<div className="account-card">
<h2>{account.name}</h2>
<p>{account.email}</p>
{/* Add more fields as necessary */}
</div>
);
};
export default Account;

View File

@@ -0,0 +1,106 @@
import React from "react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { PlusCircleIcon } from "@heroicons/react/20/solid";
import { ColumnHeadings } from "@src/lib/utils";
import styles from '../styles.module.css';
import PageHero from "@components/PageHero";
import { Suspense } from "react";
import Loading from "@src/app/components/Loading/loading";
import Link from "next/link";
export default async function AccountsTable( props: any ) {
return (
<div className="pb-12">
<div className="mt-8 flow-root">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<table className="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
className="py-3.5 pl-4 pr-3 text-left text-xs font-semibold text-gray-900 "
>
<a href="#" className="group inline-flex">
{props.newColumnHeadings.getHeading()}
<span className="invisible ml-2 flex-none rounded text-gray-400 group-hover:visible group-focus:visible">
<ChevronDownIcon
aria-hidden="true"
className="size-5"
/>
</span>
</a>
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-xs font-semibold text-gray-900"
>
<a href="#" className="group inline-flex">
{props.newColumnHeadings.getHeading()}
<span className="ml-2 flex-none rounded bg-gray-100 text-gray-900 group-hover:bg-gray-200">
<ChevronDownIcon
aria-hidden="true"
className="size-5"
/>
</span>
</a>
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-xs font-semibold text-gray-900"
>
<a href="#" className="group inline-flex">
{props.newColumnHeadings.getHeading()}
<span className="ml-2 flex-none rounded bg-gray-100 text-gray-900 group-hover:bg-gray-200">
<ChevronDownIcon
aria-hidden="true"
className="size-5"
/>
</span>
</a>
</th>
</tr>
</thead>
<tbody className=" divide-y divide-gray-200 bg-white">
{props.data.map((item: any) => (
<tr key={item.uuid}>
<td className="whitespace-wrap flex items-center py-4 pl-4 pr-3 text-xs font-medium text-gray-900 ">
<Link href={`/userProfile/${item.uuid}`}><span className="pl-2"> {item.first_name}</span></Link>
</td>
<td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900">
{item.last_name}
</td>
<td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900">
<button
type="button"
className="inline-flex items-center gap-x-1.5 rounded-xl bg-lime-800 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-lime-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-lime-900"
>
Edit
<PlusCircleIcon
aria-hidden="true"
className="-mr-0.5 size-5"
/>
</button>
</td>
<td style={{display:'none'}}>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
};

View File

@@ -1,9 +1,9 @@
import Header from "../Header"; import Header from "../Header";
import Hero from "../Hero"; import Hero from "../Hero";
import FeaturesSection from "../FeaturesSection"; import FeaturesSection from "../FeaturesSection";
import About from "../../app/site/About/page"; import About from "@siteInfo/About/page";
import Contact from "../../app/site/Contact/page"; import Contact from "@siteInfo/Contact/page";
import Footer from "../../app/site/Footer/page"; import Footer from "@siteInfo/Footer/page";
export default function HomeContent() { export default function HomeContent() {

View File

@@ -101,7 +101,7 @@ export default async function UsersTable(props: any) {
{item.last_name} {item.last_name}
</td> </td>
<td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900"> <td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900">
${item.username} {item.username}
</td> </td>
<td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900"> <td className="whitespace-nowrap px-3 py-4 text-xs text-gray-900">
<button <button

View File

@@ -12,6 +12,7 @@ const navigation = {
{ name: 'Users', href: '/Admin/Users' }, { name: 'Users', href: '/Admin/Users' },
], ],
account: [ account: [
{ name: 'Accounts', href: '/Accounts' },
{ name: 'My Account', href: '/MyAccount' }, { name: 'My Account', href: '/MyAccount' },
{ name: 'Register', href: '/signin' }, { name: 'Register', href: '/signin' },
{ name: 'Guides', href: '/Guides' }, { name: 'Guides', href: '/Guides' },

View File

@@ -1,14 +1,15 @@
// db/queries.ts // db/queries.ts
"use server"; "use server";
import { eq, not , asc} from "drizzle-orm"; import { eq, not , asc} from "drizzle-orm";
import { accounts } from '@schemas/schema' import { accounts } from '@schemas/schema';
import { db } from '../../index'; import { vw_accounts } from '@schemas/schema';
import { db } from '@db/index';
// Fetch all account // Fetch all account
export async function getAllAccounts() { export async function getAllAccounts() {
return await db.select().from(accounts); return await db.select().from(accounts);
} }
//@TODO Accounts don't have these fields, i assume next.js auth code did it this way
// Add a new account // Add a new account
export async function addAcount(first_name: string, last_name : string, username : string, password_hash: string ) { export async function addAcount(first_name: string, last_name : string, username : string, password_hash: string ) {
return await db.insert(accounts).values({ first_name, last_name, username, password_hash }).returning(); return await db.insert(accounts).values({ first_name, last_name, username, password_hash }).returning();

View File

@@ -102,6 +102,17 @@ export async function getStocks(page = 1) {
.offset(offset); .offset(offset);
} }
export async function getOptics(page = 1) {
const limit = 40;
const offset = (page - 1) * limit;
return await db.select()
.from(psa)
.limit(limit)
.where(and(like(psa.fineline, "%Optics%")))
.offset(offset);
}
export async function getStocksParts(page = 1) { export async function getStocksParts(page = 1) {
const limit = 40; const limit = 40;
const offset = (page - 1) * limit; const offset = (page - 1) * limit;

View File

@@ -1,4 +1,4 @@
import { pgTable, integer, varchar, text, numeric, timestamp, unique, check, bigserial, date, boolean, uuid, bigint, real, doublePrecision, primaryKey } from "drizzle-orm/pg-core" import { pgTable, integer, varchar, text, numeric, timestamp, unique, check, bigserial, date, boolean, uuid, bigint, real, doublePrecision, primaryKey, pgView } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm" import { sql } from "drizzle-orm"
export const products = pgTable("products", { export const products = pgTable("products", {
@@ -21,7 +21,7 @@ export const users = pgTable("users", {
.$defaultFn(() => crypto.randomUUID()), .$defaultFn(() => crypto.randomUUID()),
username: varchar({ length: 50 }).notNull(), username: varchar({ length: 50 }).notNull(),
email: varchar({ length: 255 }).notNull(), email: varchar({ length: 255 }).notNull(),
emailVerifiedOn: timestamp("emailVerifiedOn", { mode: "date" }), emailVerifiedOn: timestamp("email_verified_on", { mode: "date" }),
password_hash: varchar("password_hash", { length: 255 }).notNull(), password_hash: varchar("password_hash", { length: 255 }).notNull(),
first_name: varchar("first_name", { length: 50 }), first_name: varchar("first_name", { length: 50 }),
last_name: varchar("last_name", { length: 50 }), last_name: varchar("last_name", { length: 50 }),
@@ -425,10 +425,11 @@ export const authenticator = pgTable("authenticator", {
}); });
export const accounts = pgTable("accounts", { export const accounts = pgTable("accounts", {
userId: text().notNull(), uuid: uuid().defaultRandom(),
userId: text("user_id").notNull(),
type: text().notNull(), type: text().notNull(),
provider: text().notNull(), provider: text().notNull(),
providerAccountId: text().notNull(), providerAccountId: text("provider_account_id").notNull(),
refreshToken: text("refresh_token"), refreshToken: text("refresh_token"),
accessToken: text("access_token"), accessToken: text("access_token"),
expiresAt: integer("expires_at"), expiresAt: integer("expires_at"),
@@ -441,3 +442,21 @@ export const accounts = pgTable("accounts", {
accountProviderProviderAccountIdPk: primaryKey({ columns: [table.provider, table.providerAccountId], name: "account_provider_providerAccountId_pk"}), accountProviderProviderAccountIdPk: primaryKey({ columns: [table.provider, table.providerAccountId], name: "account_provider_providerAccountId_pk"}),
} }
}); });
export const vw_accounts = pgView("vw_accounts", {
uuid: uuid().defaultRandom(),
userId: text("user_id").notNull(),
type: text().notNull(),
provider: text().notNull(),
providerAccountId: text("provider_account_id").notNull(),
refreshToken: text("refresh_token"),
accessToken: text("access_token"),
expiresAt: integer("expires_at"),
tokenType: text("token_type"),
scope: text(),
idToken: text("id_token"),
sessionState: text("session_state"),
first_name: text("first_name"),
last_name: text("last_name"),
},).existing();

View File

@@ -46,6 +46,9 @@
"./src/components/ui/*", "./src/components/ui/*",
"./src/components/Brands/*" "./src/components/Brands/*"
], ],
"@siteInfo/*": [
"./src/app/(siteInfo)/*",
],
"@actions/*": [ "@actions/*": [
"./src/actions/*" "./src/actions/*"
], ],