From 9a0ef8e51a36e3ab45b601b977f1b5cf35d56947 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Fri, 10 Apr 2026 21:33:26 -0500 Subject: [PATCH] refactor(notification): blocking added --- .vscode/settings.json | 1 + .../notification.qualityBlocking.ts | 9 +- .../docs/notifications/lt_qualityBlocking.png | Bin 0 -> 31822 bytes frontend/src/components/Sidebar/DocBar.tsx | 105 ++++++++++++++++++ frontend/src/components/Sidebar/sidebar.tsx | 2 + frontend/src/components/ui/alert.tsx | 76 +++++++++++++ frontend/src/components/ui/collapsible.tsx | 31 ++++++ .../docs/notifications/qualityBlocking.tsx | 19 ++++ frontend/src/lib/docs.ts | 26 +++++ frontend/src/routeTree.gen.ts | 42 +++++++ 10 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 frontend/public/imgs/docs/notifications/lt_qualityBlocking.png create mode 100644 frontend/src/components/Sidebar/DocBar.tsx create mode 100644 frontend/src/components/ui/alert.tsx create mode 100644 frontend/src/components/ui/collapsible.tsx create mode 100644 frontend/src/docs/notifications/qualityBlocking.tsx create mode 100644 frontend/src/lib/docs.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 26b3786..9ab110e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -65,6 +65,7 @@ "onnotice", "opendock", "opendocks", + "palletizer", "ppoo", "preseed", "prodlabels", diff --git a/backend/notification/notification.qualityBlocking.ts b/backend/notification/notification.qualityBlocking.ts index 5dc20e8..1c7a6d6 100644 --- a/backend/notification/notification.qualityBlocking.ts +++ b/backend/notification/notification.qualityBlocking.ts @@ -10,11 +10,16 @@ import { delay } from "../utils/delay.utils.js"; import { returnFunc } from "../utils/returnHelper.utils.js"; import { sendEmail } from "../utils/sendEmail.utils.js"; import { tryCatch } from "../utils/trycatch.utils.js"; -import { v1QueryRun } from "../utils/pgConnectToLst.utils.js"; +import { v2QueryRun } from "../utils/pgConnectToLst.utils.js"; +let shutoffv1 = false const func = async (data: any, emails: string) => { // TODO: remove this disable once all 17 plants are on this new lst - v1QueryRun(`update public.notifications set active = false where name = '${data.name}'`) + if (!shutoffv1){ + v2QueryRun(`update public.notifications set active = false where name = '${data.name}'`) + shutoffv1 = true + } + const { data: l, error: le } = (await tryCatch( db.select().from(notifications).where(eq(notifications.id, data.id)), diff --git a/frontend/public/imgs/docs/notifications/lt_qualityBlocking.png b/frontend/public/imgs/docs/notifications/lt_qualityBlocking.png new file mode 100644 index 0000000000000000000000000000000000000000..98365d6950a486187de870fda8f25e6aa3a5abfb GIT binary patch literal 31822 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 H`yc)f`}y@e literal 0 HcmV?d00001 diff --git a/frontend/src/components/Sidebar/DocBar.tsx b/frontend/src/components/Sidebar/DocBar.tsx new file mode 100644 index 0000000..76cb473 --- /dev/null +++ b/frontend/src/components/Sidebar/DocBar.tsx @@ -0,0 +1,105 @@ +import { Link, useRouterState } from "@tanstack/react-router"; +import { ChevronRight } from "lucide-react"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "../ui/collapsible"; + +import { + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, + useSidebar, +} from "../ui/sidebar"; + +const docs = [ + { + title: "Notifications", + url: "/intro", + //icon, + isActive: window.location.pathname.includes("notifications") ?? false, + items: [ + { + title: "Reprints", + url: "/reprints", + }, + { + title: "New Blocking order", + url: "/qualityBlocking", + }, + ], + }, +]; +export default function DocBar() { + const { setOpen } = useSidebar(); + const pathname = useRouterState({ + select: (s) => s.location.pathname, + }); + + const isNotifications = pathname.includes("notifications"); + + return ( + + Docs + + + + + setOpen(false)}> + {/* */} + {"Intro"} + + + + + + {docs.map((item) => ( + + + + + + {item.title} + + + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + + ))} + + + + ); +} diff --git a/frontend/src/components/Sidebar/sidebar.tsx b/frontend/src/components/Sidebar/sidebar.tsx index 798509b..7c07772 100644 --- a/frontend/src/components/Sidebar/sidebar.tsx +++ b/frontend/src/components/Sidebar/sidebar.tsx @@ -7,6 +7,7 @@ import { } from "@/components/ui/sidebar"; import { useSession } from "@/lib/auth-client"; import AdminSidebar from "./AdminBar"; +import DocBar from "./DocBar"; export function AppSidebar() { const { data: session } = useSession(); @@ -21,6 +22,7 @@ export function AppSidebar() { + {session && (session.user.role === "admin" || session.user.role === "systemAdmin") && ( diff --git a/frontend/src/components/ui/alert.tsx b/frontend/src/components/ui/alert.tsx new file mode 100644 index 0000000..1fe3176 --- /dev/null +++ b/frontend/src/components/ui/alert.tsx @@ -0,0 +1,76 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground", + className + )} + {...props} + /> + ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription, AlertAction } diff --git a/frontend/src/components/ui/collapsible.tsx b/frontend/src/components/ui/collapsible.tsx new file mode 100644 index 0000000..63fc8ef --- /dev/null +++ b/frontend/src/components/ui/collapsible.tsx @@ -0,0 +1,31 @@ +import { Collapsible as CollapsiblePrimitive } from "radix-ui" + +function Collapsible({ + ...props +}: React.ComponentProps) { + return +} + +function CollapsibleTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CollapsibleContent({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/frontend/src/docs/notifications/qualityBlocking.tsx b/frontend/src/docs/notifications/qualityBlocking.tsx new file mode 100644 index 0000000..4366db0 --- /dev/null +++ b/frontend/src/docs/notifications/qualityBlocking.tsx @@ -0,0 +1,19 @@ +export default function reprints() { + return ( +
+

Quality Blocking

+ +

+ When a new blocking order is created a new alert will be sent out to all + users subscribed. if there are multiple blocking orders created between + checks you can expect to get multiple emails. below you will see an + example of a blocking email that is sent out +

+ Reprint notification example +
+ ); +} diff --git a/frontend/src/lib/docs.ts b/frontend/src/lib/docs.ts new file mode 100644 index 0000000..8479cff --- /dev/null +++ b/frontend/src/lib/docs.ts @@ -0,0 +1,26 @@ +import type { ComponentType } from "react"; + +const modules = import.meta.glob("../docs/**/*.tsx", { + eager: true, +}); + +type DocModule = { + default: ComponentType; +}; + +const docsMap: Record = {}; + +for (const path in modules) { + const mod = modules[path] as DocModule; + + const slug = path + .replace("../docs/", "") + .replace(".tsx", ""); + + // "notifications/intro" + docsMap[slug] = mod.default; +} + +export function getDoc(slug: string) { + return docsMap[slug]; +} \ No newline at end of file diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 35b7ff1..1412139 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -11,6 +11,8 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as AboutRouteImport } from './routes/about' import { Route as IndexRouteImport } from './routes/index' +import { Route as DocsIndexRouteImport } from './routes/docs/index' +import { Route as DocsSplatRouteImport } from './routes/docs/$' import { Route as AdminSettingsRouteImport } from './routes/admin/settings' import { Route as AdminNotificationsRouteImport } from './routes/admin/notifications' import { Route as AdminLogsRouteImport } from './routes/admin/logs' @@ -29,6 +31,16 @@ const IndexRoute = IndexRouteImport.update({ path: '/', getParentRoute: () => rootRouteImport, } as any) +const DocsIndexRoute = DocsIndexRouteImport.update({ + id: '/docs/', + path: '/docs/', + getParentRoute: () => rootRouteImport, +} as any) +const DocsSplatRoute = DocsSplatRouteImport.update({ + id: '/docs/$', + path: '/docs/$', + getParentRoute: () => rootRouteImport, +} as any) const AdminSettingsRoute = AdminSettingsRouteImport.update({ id: '/admin/settings', path: '/admin/settings', @@ -72,6 +84,8 @@ export interface FileRoutesByFullPath { '/admin/logs': typeof AdminLogsRoute '/admin/notifications': typeof AdminNotificationsRoute '/admin/settings': typeof AdminSettingsRoute + '/docs/$': typeof DocsSplatRoute + '/docs/': typeof DocsIndexRoute '/user/profile': typeof authUserProfileRoute '/user/resetpassword': typeof authUserResetpasswordRoute '/user/signup': typeof authUserSignupRoute @@ -83,6 +97,8 @@ export interface FileRoutesByTo { '/admin/logs': typeof AdminLogsRoute '/admin/notifications': typeof AdminNotificationsRoute '/admin/settings': typeof AdminSettingsRoute + '/docs/$': typeof DocsSplatRoute + '/docs': typeof DocsIndexRoute '/user/profile': typeof authUserProfileRoute '/user/resetpassword': typeof authUserResetpasswordRoute '/user/signup': typeof authUserSignupRoute @@ -95,6 +111,8 @@ export interface FileRoutesById { '/admin/logs': typeof AdminLogsRoute '/admin/notifications': typeof AdminNotificationsRoute '/admin/settings': typeof AdminSettingsRoute + '/docs/$': typeof DocsSplatRoute + '/docs/': typeof DocsIndexRoute '/(auth)/user/profile': typeof authUserProfileRoute '/(auth)/user/resetpassword': typeof authUserResetpasswordRoute '/(auth)/user/signup': typeof authUserSignupRoute @@ -108,6 +126,8 @@ export interface FileRouteTypes { | '/admin/logs' | '/admin/notifications' | '/admin/settings' + | '/docs/$' + | '/docs/' | '/user/profile' | '/user/resetpassword' | '/user/signup' @@ -119,6 +139,8 @@ export interface FileRouteTypes { | '/admin/logs' | '/admin/notifications' | '/admin/settings' + | '/docs/$' + | '/docs' | '/user/profile' | '/user/resetpassword' | '/user/signup' @@ -130,6 +152,8 @@ export interface FileRouteTypes { | '/admin/logs' | '/admin/notifications' | '/admin/settings' + | '/docs/$' + | '/docs/' | '/(auth)/user/profile' | '/(auth)/user/resetpassword' | '/(auth)/user/signup' @@ -142,6 +166,8 @@ export interface RootRouteChildren { AdminLogsRoute: typeof AdminLogsRoute AdminNotificationsRoute: typeof AdminNotificationsRoute AdminSettingsRoute: typeof AdminSettingsRoute + DocsSplatRoute: typeof DocsSplatRoute + DocsIndexRoute: typeof DocsIndexRoute authUserProfileRoute: typeof authUserProfileRoute authUserResetpasswordRoute: typeof authUserResetpasswordRoute authUserSignupRoute: typeof authUserSignupRoute @@ -163,6 +189,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } + '/docs/': { + id: '/docs/' + path: '/docs' + fullPath: '/docs/' + preLoaderRoute: typeof DocsIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/docs/$': { + id: '/docs/$' + path: '/docs/$' + fullPath: '/docs/$' + preLoaderRoute: typeof DocsSplatRouteImport + parentRoute: typeof rootRouteImport + } '/admin/settings': { id: '/admin/settings' path: '/admin/settings' @@ -222,6 +262,8 @@ const rootRouteChildren: RootRouteChildren = { AdminLogsRoute: AdminLogsRoute, AdminNotificationsRoute: AdminNotificationsRoute, AdminSettingsRoute: AdminSettingsRoute, + DocsSplatRoute: DocsSplatRoute, + DocsIndexRoute: DocsIndexRoute, authUserProfileRoute: authUserProfileRoute, authUserResetpasswordRoute: authUserResetpasswordRoute, authUserSignupRoute: authUserSignupRoute,