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 0000000..98365d6 Binary files /dev/null and b/frontend/public/imgs/docs/notifications/lt_qualityBlocking.png differ 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,