Compare commits

...

9 Commits

81 changed files with 11837 additions and 501 deletions

48
.vscode/settings copy.json.bak vendored Normal file
View File

@@ -0,0 +1,48 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"workbench.colorTheme": "Default Dark+",
"prettier.tabWidth": 4,
"terminal.integrated.env.windows": {},
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"[graphql]": {
"editor.formatOnSave": true
},
"[handlebars]": {
"editor.formatOnSave": true
},
"[go]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "golang.go"
},
"[powershell]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-vscode.powershell" // requires PowerShell extension
},
"[bat]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "foxundermoon.shell-format" // supports .sh, .bat, .cmd
},
"[cmd]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "foxundermoon.shell-format"
},
// Optional: Configure goimports instead of gofmt
"go.formatTool": "goimports",
"cSpell.words": ["alpla", "alplamart", "alplaprod", "ppoo"]
}

45
.vscode/settings.json vendored
View File

@@ -1,48 +1,9 @@
{ {
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "biomejs.biome",
"workbench.colorTheme": "Default Dark+", "workbench.colorTheme": "Default Dark+",
"prettier.tabWidth": 4,
"terminal.integrated.env.windows": {}, "terminal.integrated.env.windows": {},
"editor.formatOnSave": true, "editor.formatOnSave": true,
"[javascript]": { "editor.codeActionsOnSave": {"source.fixAll.biome": "explicit",
"editor.formatOnSave": true "source.organizeImports.biome": "explicit" },
},
"[javascriptreact]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"[graphql]": {
"editor.formatOnSave": true
},
"[handlebars]": {
"editor.formatOnSave": true
},
"[go]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "golang.go"
},
"[powershell]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-vscode.powershell" // requires PowerShell extension
},
"[bat]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "foxundermoon.shell-format" // supports .sh, .bat, .cmd
},
"[cmd]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "foxundermoon.shell-format"
},
// Optional: Configure goimports instead of gofmt
"go.formatTool": "goimports",
"cSpell.words": ["alpla", "alplamart", "alplaprod", "ppoo"] "cSpell.words": ["alpla", "alplamart", "alplaprod", "ppoo"]
} }

View File

@@ -0,0 +1,21 @@
meta {
name: Get Consumption
type: http
seq: 1
}
get {
url: {{urlv2}}/api/eom/productionconsumption?startDate=9/1/2025&endDate=9/30/2025&includePlantToken=true
body: none
auth: inherit
}
params:query {
startDate: 9/1/2025
endDate: 9/30/2025
includePlantToken: true
}
settings {
encodeUrl: true
}

View File

@@ -0,0 +1,8 @@
meta {
name: EOM
seq: 4
}
auth {
mode: inherit
}

View File

@@ -1,7 +1,7 @@
meta { meta {
name: GrantROle by ID name: GrantROle by ID
type: http type: http
seq: 8 seq: 7
} }
post { post {

View File

@@ -0,0 +1,8 @@
meta {
name: User
seq: 2
}
auth {
mode: inherit
}

View File

@@ -16,10 +16,10 @@ headers {
body:json { body:json {
{ {
"name": "Bethlehem", "name": "Bowling Green 2",
"serverDNS": "USBET1VMS006", "serverDNS": "USBOW2VMS006",
"plantToken": "usbet1", "plantToken": "usbow2",
"ipAddress": "10.204.0.26", "ipAddress": "10.30.0.26",
"greatPlainsPlantCode": 0, "greatPlainsPlantCode": 0,
"lstServerPort": 4000, "lstServerPort": 4000,
"serverLoc": "E$\\LST" "serverLoc": "E$\\LST"

View File

@@ -14,6 +14,10 @@ params:path {
token: usbet1 token: usbet1
} }
headers {
Cookie: {{session_cookie}}
}
body:json { body:json {
{ {
"zipcode": 45245 "zipcode": 45245

View File

@@ -1,7 +1,7 @@
meta { meta {
name: Get user Roles name: Get user Roles
type: http type: http
seq: 9 seq: 7
} }
get { get {

View File

@@ -1,7 +1,7 @@
meta { meta {
name: Request Resetpassword name: Request Resetpassword
type: http type: http
seq: 10 seq: 8
} }
post { post {

View File

@@ -1,11 +1,11 @@
meta { meta {
name: Resetpassword name: Resetpassword
type: http type: http
seq: 11 seq: 9
} }
post { post {
url: http://localhost:4200/lst/api/auth/reset-password url: {{url}}/lst/api/auth/reset-password
body: json body: json
auth: inherit auth: inherit
} }

View File

@@ -1,7 +1,7 @@
vars { vars {
url: http://localhost:4200 url: http://localhost:4200
session_cookie: session_cookie:
urlv2: http://usksc1vms006:3000 urlv2: http://usiow1vms006:3001
jwtV2: jwtV2:
} }
vars:secret [ vars:secret [

View File

@@ -19,10 +19,13 @@ import { sendNotify } from "./src/pkg/utils/notify.js";
import { toNodeHandler } from "better-auth/node"; import { toNodeHandler } from "better-auth/node";
import { auth } from "./src/pkg/auth/auth.js"; import { auth } from "./src/pkg/auth/auth.js";
import { apiHitMiddleware } from "./src/pkg/middleware/apiHits.js"; import { apiHitMiddleware } from "./src/pkg/middleware/apiHits.js";
import { setupIoServer } from "./src/ws/server.js";
import { schedulerManager } from "./src/internal/logistics/controller/schedulerManager.js";
const main = async () => { const main = async () => {
const env = validateEnv(process.env); const env = validateEnv(process.env);
const PORT = Number(env.VITE_PORT) || 4200; const PORT = Number(env.VITE_PORT) || 4200;
//create the logger //create the logger
const log = createLogger({ module: "system", subModule: "main start" }); const log = createLogger({ module: "system", subModule: "main start" });
@@ -130,16 +133,18 @@ const main = async () => {
express.static(join(__dirname, "../frontend/dist")) express.static(join(__dirname, "../frontend/dist"))
); );
// server setup
const server = createServer(app);
// register app // register app
setupRoutes(app, basePath); setupRoutes(app, basePath);
// ws stuff // ws stuff
setupIoServer(server, basePath);
// ws + server stuff
const server = createServer(app);
// sub systems // sub systems
printers(); printers();
schedulerManager();
// start the server up // start the server up
server.listen(PORT, "0.0.0.0", () => server.listen(PORT, "0.0.0.0", () =>

View File

@@ -0,0 +1,122 @@
import { subMinutes } from "date-fns";
import { format, formatInTimeZone } from "date-fns-tz";
import { sql } from "drizzle-orm";
import { db } from "../../../pkg/db/db.js";
import {
type OrderScheduler,
orderScheduler,
} from "../../../pkg/db/schema/orderScheduler.js";
import { createLogger } from "../../../pkg/logger/logger.js";
import { prodQuery } from "../../../pkg/prodSql/prodQuery.js";
import { scheduler } from "../../../pkg/prodSql/querys/scheduler/scheduler.js";
import { tryCatch } from "../../../pkg/utils/tryCatch.js";
/*
will monitor the incoming goods and the orders and update lst as they change or get updated.
*/
export const schedulerManager = async () => {
const log = createLogger({
module: "logistics",
subModule: "scheduleManager",
});
log.info({}, "Starting the scheduler manager up.");
setInterval(async () => {
const targetTimeZone = "America/New_York";
const now = new Date();
// console.log(formatInTimeZone(now, targetTimeZone, "yyyy-M-d HH:mm"));
// console.log(format(now, "yyyy-M-d HH:mm"));
const { data, error } = (await tryCatch(
prodQuery(
scheduler.replace(
"[dateCheck]",
formatInTimeZone(
subMinutes(now, 1), // dealing with the 1 min difference in case we have something missed.
targetTimeZone,
"yyyy-M-d HH:mm",
),
),
"scheduler",
),
)) as any;
// do the updates to the db so we can pull the info up to the frontend
if (error) {
log.error({ error: error }, "there was an error getting the data");
return;
}
const orderData = data.data || ([] as OrderScheduler);
//console.log(data);
if (orderData.length === 0) {
log.info({}, "There are no new orders or incoming to be updated");
return;
}
for (let i = 0; i < orderData.length; i++) {
const { data, error } = await tryCatch(
db
.insert(orderScheduler)
.values({
av: orderData[i].av,
description: orderData[i].description,
orderType: orderData[i].type, //orders || incoming
orderNumber: orderData[i].orderNumber,
header: orderData[i].av,
lineItemNumber: orderData[i].lineItemNumber,
customerReleaseNumber: orderData[i].customerReleaseNumber,
deliveryDate: new Date(orderData[i].deliveryDate),
loadingDate: new Date(orderData[i].loadingDate),
orderQTY: orderData[i].orderQTY,
orderLu: orderData[i].orderLu,
deliveredQTY: orderData[i].deliveredQTY,
deliveredLu: orderData[i].deliveredLu,
remark: orderData[i].remark,
createdAsEDI: orderData[i].createdAsEDI,
currentState: orderData[i].currentState,
lstDateCheck: new Date(orderData[i].deliveryDate), //this will match the delivery date to start
customerAddressId: orderData[i].customerAddressId,
customerDescription: orderData[i].customerDescription,
orderFrom: "prod", // manual or prod.
// being edited change to true so it will essential lock all others from editing
// carrier
// carrier email. -- when dropped we can email the carrier this could be considered there confirmation.
addDate: sql`NOW()`,
updDate: sql`NOW()`,
})
.onConflictDoUpdate({
target: orderScheduler.orderNumber,
set: {
deliveryDate: new Date(orderData[i].deliveryDate),
loadingDate: new Date(orderData[i].loadingDate),
orderQTY: orderData[i].orderQTY,
orderLu: orderData[i].orderLu,
remark: orderData[i].remark,
currentState: orderData[i].currentState,
deliveredQTY: orderData[i].deliveredQTY,
deliveredLu: orderData[i].deliveredLu,
lstDateCheck: new Date(orderData[i].deliveryDate),
updDate: sql`NOW()`,
},
}),
);
if (error) {
console.log(error);
log.error(
{ error: error },
`There was an error inserting/updating the order ${orderData[i].orderNumber}`,
);
continue;
}
log.info(
{ data: data },
`${orderData[i].orderNumber} was inserted or updated`,
);
//await delay
}
}, 60 * 1000);
};

View File

@@ -0,0 +1,16 @@
import type { Express, Request, Response } from "express";
import { requireAuth } from "../../pkg/middleware/authMiddleware.js";
import schedule from "./routes/scheduler/scheduleRoutes.js";
export const setupLogisticsRoutes = (app: Express, basePath: string) => {
app.use(basePath + "/api/logistics/schedule", schedule);
app.use(
basePath + "/api/admin/users",
requireAuth("user", ["systemAdmin"]) // will pass bc system admin but this is just telling us we need this
);
app.use(
basePath + "/api/admin",
requireAuth("user", ["systemAdmin", "admin"]) // will pass bc system admin but this is just telling us we need this
);
};

View File

@@ -0,0 +1,12 @@
import { Router } from "express";
import type { Request, Response } from "express";
import { schedulerChange } from "../../../../ws/channels/scheduler.js";
const router = Router();
router.get("/", async (req: Request, res: Response) => {
schedulerChange({ name: "something" });
res.status(200).json({ message: "Something " });
});
export default router;

View File

@@ -0,0 +1,32 @@
import { Router } from "express";
import getSchedule from "./getSchedule.js";
import { restrictToHosts } from "../../../../pkg/middleware/restrictToHosts.js";
import { requireAuth } from "../../../../pkg/middleware/authMiddleware.js";
const router = Router();
router.use("/", getSchedule);
// router.use(
// "/",
// requireAuth("user", ["systemAdmin", "admin"]),
// restrictToHosts([
// "usmcd1vms036.alpla.net",
// "USMCD1VMS036.alpla.net",
// "https://usmcd1vms036.alpla.net",
// ]),
// addServer
// );
// router.use(
// "/",
// requireAuth("user", ["systemAdmin", "admin"]),
// restrictToHosts([
// "usmcd1vms036.alpla.net",
// "USMCD1VMS036.alpla.net",
// "https://usmcd1vms036.alpla.net",
// ]),
// updateServer
// );
export default router;

View File

@@ -2,12 +2,14 @@ import type { Express, Request, Response } from "express";
import { setupAuthRoutes } from "../auth/routes/routes.js"; import { setupAuthRoutes } from "../auth/routes/routes.js";
import { setupAdminRoutes } from "../admin/routes.js"; import { setupAdminRoutes } from "../admin/routes.js";
import { setupSystemRoutes } from "../system/routes.js"; import { setupSystemRoutes } from "../system/routes.js";
import { setupLogisticsRoutes } from "../logistics/routes.js";
export const setupRoutes = (app: Express, basePath: string) => { export const setupRoutes = (app: Express, basePath: string) => {
// all routes // all routes
setupAuthRoutes(app, basePath); setupAuthRoutes(app, basePath);
setupAdminRoutes(app, basePath); setupAdminRoutes(app, basePath);
setupSystemRoutes(app, basePath); setupSystemRoutes(app, basePath);
setupLogisticsRoutes(app, basePath);
// always try to go to the app weather we are in dev or in production. // always try to go to the app weather we are in dev or in production.
app.get(basePath + "/", (req: Request, res: Response) => { app.get(basePath + "/", (req: Request, res: Response) => {

View File

@@ -0,0 +1,51 @@
import {
boolean,
date,
integer,
pgTable,
real,
text,
timestamp,
uniqueIndex,
uuid,
} from "drizzle-orm/pg-core";
import type z from "zod";
export const orderScheduler = pgTable(
"orderScheduler",
{
schedule_id: uuid("schedule_id").defaultRandom().primaryKey(),
av: integer("av"),
description: text("description"),
orderType: text("order_type").notNull(), //orders || incoming
orderNumber: integer("order_number").notNull(),
header: text("header").notNull(),
lineItemNumber: text("line_item_number"),
customerReleaseNumber: text("customer_release_number"),
deliveryDate: timestamp("delivery_date").notNull(),
loadingDate: timestamp("loading_date"),
orderQTY: real("order_qty").notNull(),
orderLu: real("order_lu").notNull(),
deliveredQTY: real("delivered_qty").default(0.0),
deliveredLu: real("delivered_lu").default(0.0),
remark: text("remark"),
createdAsEDI: boolean("created_as_EDI"),
currentState: integer("current_state"),
lstDateCheck: timestamp("lst_date_check"), //this will match the delivery date to start and when moved in the front end run a function to alert or update via api
customerAddressId: integer("customer_address_id"),
customerDescription: text("customer_description"),
dock: text("dock"),
orderFrom: text("order_from"), // manual or prod.
// being edited change to true so it will essential lock all others from editing
// carrier
// carrier email. -- when dropped we can email the carrier this could be considered there confirmation.
addDate: timestamp("add_date").defaultNow(),
updDate: timestamp("upd_date").defaultNow(),
},
(table) => [
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
uniqueIndex("orderNumber").on(table.orderNumber),
],
);
export type OrderScheduler = z.infer<typeof orderScheduler>;

View File

@@ -1,11 +1,11 @@
import { import {
text,
pgTable,
timestamp,
uuid,
uniqueIndex,
jsonb,
boolean, boolean,
jsonb,
pgTable,
text,
timestamp,
uniqueIndex,
uuid,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod"; import { createInsertSchema, createSelectSchema } from "drizzle-zod";
@@ -29,7 +29,7 @@ export const settings = pgTable(
(table) => [ (table) => [
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
uniqueIndex("name").on(table.name), uniqueIndex("name").on(table.name),
] ],
); );
export const settingSchema = createSelectSchema(settings); export const settingSchema = createSelectSchema(settings);

View File

@@ -1,6 +1,6 @@
import build from "pino-abstract-transport"; import build from "pino-abstract-transport";
import { db } from "../db/db.js"; import { db } from "../db/db.js";
import { logs, type Log } from "../db/schema/logs.js"; import { type Log, logs } from "../db/schema/logs.js";
import { tryCatch } from "../utils/tryCatch.js"; import { tryCatch } from "../utils/tryCatch.js";
const pinoLogLevels: any = { const pinoLogLevels: any = {
@@ -15,8 +15,8 @@ const pinoLogLevels: any = {
export default async function (log: Log) { export default async function (log: Log) {
//const {username, service, level, msg, ...extra} = log; //const {username, service, level, msg, ...extra} = log;
try { try {
return build(async function (source) { return build(async (source) => {
for await (let obj of source) { for await (const obj of source) {
// convert to the name to make it more easy to find later :P // convert to the name to make it more easy to find later :P
const levelName = pinoLogLevels[obj.level] || "unknown"; const levelName = pinoLogLevels[obj.level] || "unknown";
@@ -28,7 +28,7 @@ export default async function (log: Log) {
hostname: obj?.hostname?.toLowerCase(), hostname: obj?.hostname?.toLowerCase(),
message: obj.msg, message: obj.msg,
stack: obj?.stack, stack: obj?.stack,
}) }),
); );
if (res.error) { if (res.error) {

View File

@@ -1,6 +1,6 @@
import pino, { type Logger } from "pino"; import pino, { type Logger } from "pino";
export let logLevel = process.env.LOG_LEVEL || "info"; export const logLevel = process.env.LOG_LEVEL || "info";
const transport = pino.transport({ const transport = pino.transport({
targets: [ targets: [
@@ -37,7 +37,7 @@ export const rootLogger: Logger = pino(
level: logLevel, level: logLevel,
redact: { paths: ["email", "password"], remove: true }, redact: { paths: ["email", "password"], remove: true },
}, },
transport transport,
); );
/** /**

View File

@@ -1,7 +1,8 @@
import build from "pino-abstract-transport"; import build from "pino-abstract-transport";
import { type Log } from "../db/schema/logs.js"; import type { Log } from "../db/schema/logs.js";
import { validateEnv } from "../utils/envValidator.js"; import { validateEnv } from "../utils/envValidator.js";
import { sendNotify } from "../utils/notify.js"; import { sendNotify } from "../utils/notify.js";
const env = validateEnv(process.env); const env = validateEnv(process.env);
const pinoLogLevels: any = { const pinoLogLevels: any = {
@@ -17,16 +18,14 @@ const pinoLogLevels: any = {
export default async function (log: Log) { export default async function (log: Log) {
//const {username, service, level, msg, ...extra} = log; //const {username, service, level, msg, ...extra} = log;
try { try {
return build(async function (source) { return build(async (source) => {
for await (let obj of source) { for await (const obj of source) {
// convert to the name to make it more easy to find later :P // convert to the name to make it more easy to find later :P
const levelName = pinoLogLevels[obj.level] || "unknown"; const levelName = pinoLogLevels[obj.level] || "unknown";
const newlog = { const newlog = {
level: levelName, level: levelName,
module: obj.module module: obj.module ? String(obj.module).toLowerCase() : undefined,
? String(obj.module).toLowerCase()
: undefined,
subModule: obj.subModule subModule: obj.subModule
? String(obj.subModule).toLowerCase() ? String(obj.subModule).toLowerCase()
: undefined, : undefined,

View File

@@ -23,16 +23,15 @@ export async function prodQuery(queryToRun: string, name: string) {
}); });
} }
const query = queryToRun.replaceAll("test1", env.PROD_PLANT_TOKEN); const query = queryToRun.replaceAll("test1", env.PROD_PLANT_TOKEN);
try { try {
const result = await pool.request().query(query); const result = await pool.request().query(query);
return { return {
success: true, success: true,
message: `Query results for: ${name}`, message: `Query results for: ${name}`,
data: result.recordset, data: result.recordset,
}; };
} catch (error: any) { } catch (error: any) {
console.log(error);
if (error.code === "ETIMEOUT") { if (error.code === "ETIMEOUT") {
return returnFunc({ return returnFunc({
success: false, success: false,
@@ -51,7 +50,7 @@ export async function prodQuery(queryToRun: string, name: string) {
module: "prodSql", module: "prodSql",
subModule: "query", subModule: "query",
level: "error", level: "error",
message: `${name} encoutnered an error ${error.originalError.info.message}`, message: `${name} encountered an error ${error.originalError.info.message}`,
data: [], data: [],
}); });
} }

View File

@@ -38,7 +38,7 @@ export const initializeProdPool = async () => {
}); });
} }
try { try {
pool = sql.connect(sqlConfig); pool = await sql.connect(sqlConfig);
log.info( log.info(
`Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}` `Connected to ${sqlConfig?.server}, using DB: ${sqlConfig?.database}`

View File

@@ -0,0 +1,109 @@
export const scheduler = `
use AlplaPROD_test1
/*
This query will combine both the incoming goods and the deliveries in 1 as it will be the query that populates into lst db then later updated
*/
DECLARE @checkDateString NVARCHAR(MAX) = '[dateCheck]' --'2025-10-14 08:00'; -- will be passed over to validate new updates.
DECLARE @checkDate DATETIME2 = CONVERT(datetime2, @checkDateString);
-- orders
select * from (select
type = 'orders'
,l.ArticleHumanReadableId as av
,l.ArticleDescription as description
,[ReleaseNumber] as orderNumber
,h.CustomerOrderNumber as header
,l.CustomerLineItemNumber as lineItemNumber
,CustomerReleaseNumber as customerReleaseNumber
,FORMAT(r.[Deliverydate], 'yyyy-MM-dd HH:mm') as deliveryDate
,FORMAT([LoadingDate], 'yyyy-MM-dd HH:mm') as loadingDate
,[Quantity] as orderQTY
,[LoadingUnits] as orderLu
,case when t.GelieferteMenge is null then 0 else t.GelieferteMenge end as deliveredQTY
,case when t.GelieferteMengeVPK is null then 0 else t.GelieferteMengeVPK end as deliveredLu
,r.Remark as remark
,h.CreatedByEdi as createdAsEDI -- if 1 then we run the new function to change this in true edi as well as lstdb.
,r.ReleaseState as currentState -- anything other than 0 should lock this and not allow for changes
--,lstDate = getdate() --'this is a place holder for date see edi comment'
--,dock = 'dock3' --another place holder for what dock we will go to'
--,orderType = 'maunal or prod' -- this is for if we manually add in the order from lst. this way the dates will be ignored if this is manual.
,h.CustomerHumanReadableId as addressId
,h.CustomerDescription as customer
,orderType = 20
,r.[Add_User]
,r.[Add_Date]
,r.[Upd_User]
,r.[Upd_Date]
FROM [test1_AlplaPROD2.0_Reporting].[reporting_order].[Release] as r
left join
[test1_AlplaPROD2.0_Reporting].[reporting_order].LineItem as l on
l.id = r.LineItemId
left join
[test1_AlplaPROD2.0_Read].[order].Header as h on
h.Id = l.HeaderId
left join
dbo.V_TrackerAuftragsAbrufe (nolock) as t on
t.IdAuftragsAbruf = r.ReleaseNumber
--where r.[Upd_Date] >= getdate() -@age
where CAST(r.[Upd_Date] AS datetime2) >= @checkDate
union all
-- incoming goods
select
type = 'incoming'
,inc.IdArtikelVarianten as av
,av.Bezeichnung as description
,IdBestellung as orderNumber
,case when inc.Bemerkung <> '' then case when CHARINDEX(',',inc.Bemerkung) = 0 then inc.Bemerkung else left(inc.Bemerkung, CHARINDEX(',',inc.Bemerkung) -1) end else 'Missing PO' end as header
,case when inc.Bemerkung <> '' then case when CHARINDEX(',',inc.Bemerkung) = 0 then inc.Bemerkung else left(inc.Bemerkung, CHARINDEX(',',inc.Bemerkung) -1) end else 'Missing PO' end as lineItemNumber
,case when inc.Bemerkung <> '' then case when CHARINDEX(',',inc.Bemerkung) = 0 then inc.Bemerkung else left(inc.Bemerkung, CHARINDEX(',',inc.Bemerkung) -1) end else 'Missing PO' end as customerReleaseNumber
,FORMAT(inc.Datum, 'yyyy-MM-dd HH:mm') as deliveryDate
,FORMAT(inc.Datum, 'yyyy-MM-dd HH:mm') as loadingDate
,sollMenge as orderQty
,sollmengevpk as orderLu
,case when l.EntladeMenge is null then 0 else l.EntladeMenge end as deliveredQTY
,case when l.EntladeMengeVPK is null then 0 else l.EntladeMengeVPK end as deliveredLu
,inc.Bemerkung as remark
,createdAsEDI = 0
,inc.Status as currentState -- anything other than 0 should lock this and not allow for changes
--,lstDate = getdate() --'this is a place holder for date see edi comment'
--,dock = 'dock3' --another place holder for what dock we will go to'
--,orderType = 'maunal or prod' -- this is for if we manually add in the order from lst. this way the dates will be ignored if this is manual.
,inc.IdAdresse as addressId
,a.Bezeichnung
,inc.Typ as orderType -- this is just the id
,inc.Add_User
,inc.Add_Date
,inc.Upd_User
,inc.Upd_Date
from T_Wareneingaenge (nolock) as inc
--article stuff
left join
T_Artikelvarianten (nolock) as av on
av.IdArtikelvarianten = inc.IdArtikelVarianten
left join
T_WareneingangAuftraege (nolock) as w on
w.Beleg = inc.Beleg
left join
T_WareneingangPlanungen (nolock) as l on
l.IdWareneingangAuftrag = w.IdWareneingangAuftrag
left join
T_adressen as a on
a.idadressen = inc.IdAdresse
--where inc.Upd_Date >= getdate() -@age
where inc.Upd_Date >= @checkDate
--and inc.Typ not in (40)
)a
order by upd_date desc
`;

View File

@@ -0,0 +1,15 @@
import { validateEnv } from "./envValidator.js";
const env = validateEnv(process.env);
// export const allowedOrigins = [
// /^https?:\/\/localhost:(5173|5500|4200|3000|4000)$/, // all the allowed backend ports
// /^http?:\/\/localhost:(5173|5500|4200|3000|4000)$/,
// /^https?:\/\/.*\.alpla\.net$/,
// env.BETTER_AUTH_URL, // prod
// ];
export const allowedOrigins: (string | RegExp)[] = [
/^https?:\/\/localhost:(5173|5500|4200|3000|4000)$/, // all local dev ports
/^https?:\/\/.*\.alpla\.net$/, // any subdomain of alpla.net
env.BETTER_AUTH_URL, // production URL
];

View File

View File

@@ -0,0 +1,43 @@
import { Namespace, Socket } from "socket.io";
import { requireAuth } from "../../pkg/middleware/authMiddleware.js";
export const setupAllLogs = (io: Namespace) => {
// Wrap middleware for Socket.IO
io.use(async (socket: Socket, next) => {
try {
// Mock Express req/res object
const req = socket.request as any;
// Create a mini next function that throws an error if unauthorized
await new Promise<void>((resolve, reject) => {
const fakeRes: any = {
status: () => ({
json: (obj: any) => reject(new Error(obj.error)),
}),
};
const nextFn = (err?: any) => (err ? reject(err) : resolve());
// Call your middleware
requireAuth("", ["systemAdmin", "admin"])(req, fakeRes, nextFn);
});
// Auth passed
next();
} catch (err: any) {
next(new Error(err.message || "Unauthorized"));
}
});
io.on("connection", (socket: Socket) => {
console.log(
"✅ Authenticated client connected to channel2:",
socket.id
);
socket.on("ping", () => socket.emit("pong"));
socket.on("disconnect", () => {
console.log("🔴 Client disconnected from channel2:", socket.id);
});
});
};

View File

@@ -0,0 +1,59 @@
import { formatDate } from "date-fns";
import type { Server, Socket } from "socket.io";
import { db } from "../../pkg/db/db.js";
import { orderScheduler } from "../../pkg/db/schema/orderScheduler.js";
import { tryCatch } from "../../pkg/utils/tryCatch.js";
let ioInstance: Server | null = null;
export const setupScheduler = (io: Server, socket: Socket) => {
ioInstance = io;
socket.on("joinScheduler", async () => {
socket.join("scheduler");
//console.log(`Socket ${socket.id} joined room "scheduler"`);
const { data, error } = await tryCatch(db.select().from(orderScheduler));
if (error) {
setTimeout(() => {
io.to("scheduler").emit("scheduler:update", {
type: "init",
error: error,
});
}, 1000);
return;
}
// initial push
setTimeout(() => {
io.to("scheduler").emit("scheduler:update", { type: "init", data: data });
}, 1000);
});
// socket.on("ping", () => {
// io.to("scheduler").emit("pong", { from: socket.id });
// });
// setInterval(() => {
// io.to("scheduler").emit("heartbeat", {
// ts: formatDate(Date.now(), "M/d/yyyy HH:mm"),
// });
// }, 60_000);
// add in listen for changes to the db with pg listen?
};
// --- Change Broadcast Function ---
export const schedulerChange = async (data: any) => {
if (!ioInstance) {
console.error("⚠️ schedulerChange called before setupScheduler initialized");
return;
}
ioInstance.to("scheduler").emit("scheduler:update", {
ts: formatDate(Date.now(), "M/d/yyyy HH:mm"),
data,
});
console.log("📢 Scheduler update broadcasted:", data);
};

66
app/src/ws/server.ts Normal file
View File

@@ -0,0 +1,66 @@
import { Server } from "socket.io";
import type { Server as HttpServer } from "http";
import { allowedOrigins } from "../pkg/utils/corsController.js";
import { setupScheduler } from "./channels/scheduler.js";
export const setupIoServer = async (server: HttpServer, basePath: string) => {
const io = new Server(server, {
path: `${basePath}/api/ws`,
cors: {
// origin: ["http://localhost:5500"],
origin: (origin, callback) => {
// Allow non-browser clients (Postman, direct websocket, etc.)
if (!origin) return callback(null, true);
try {
// Check if origin matches any allowed string or regex
const allowed = allowedOrigins.some((o) => {
if (typeof o === "string") return o === origin;
if (o instanceof RegExp) return o.test(origin);
return false;
});
if (allowed) {
return callback(null, true);
}
} catch (err) {
console.error("Invalid Origin header:", origin);
}
// Deny all others
return callback(new Error("Not allowed by CORS: " + origin));
},
// methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
credentials: true,
},
pingInterval: 25_000, // send ping every 25s (default 25s)
pingTimeout: 60_000, // wait 60s before disconnecting (default 60s)
});
io.on("connection", (socket) => {
console.log("🟢 User connected:", socket.id);
// Join a room
socket.on("joinRoom", (room: string) => {
socket.join(room);
console.log(`Socket ${socket.id} joined room ${room}`);
});
// Leave a room
socket.on("leaveRoom", (room: string) => {
socket.leave(room);
console.log(`Socket ${socket.id} left room ${room}`);
});
// Example: broadcast a message to a room
socket.on("message", ({ room, payload }) => {
io.to(room).emit("message", payload);
});
socket.on("disconnect", (reason) => {
console.log("🔴 User disconnected:", socket.id, reason);
});
setupScheduler(io, socket);
});
};

45
biome.json Normal file
View File

@@ -0,0 +1,45 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.6/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"files": {
"ignoreUnknown": false
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
},
"linter": {
"enabled": false,
"rules": {
"suspicious": {
"noConsole": {
"options": {
"allow": ["error", "info"]
}
}
},
"correctness": {
"useJsxKeyInIterable": "error"
}
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"recommended": true,
"organizeImports": "on"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
}
}

View File

@@ -0,0 +1,11 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(logistics)/logistics/deliverySchedule')(
{
component: RouteComponent,
},
)
function RouteComponent() {
return <div>Hello "/(logistics)/logistics/deliverySchedule"!</div>
}

View File

@@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(mobileStuff)/_mobileLayout/')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/(mobileStuff)/_mobileLayout/"!</div>
}

View File

@@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(mobileStuff)/_mobileLayout/m/')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/(mobileStuff)/_mobileLayout/m/"!</div>
}

View File

@@ -8,11 +8,14 @@
"name": "frontend", "name": "frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1",
"@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7", "@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
@@ -22,14 +25,22 @@
"@tanstack/react-query": "^5.89.0", "@tanstack/react-query": "^5.89.0",
"@tanstack/react-router": "^1.131.36", "@tanstack/react-router": "^1.131.36",
"@tanstack/react-router-devtools": "^1.131.36", "@tanstack/react-router-devtools": "^1.131.36",
"@types/react-calendar-timeline": "^0.28.6",
"axios": "^1.12.2", "axios": "^1.12.2",
"better-auth": "^1.3.11", "better-auth": "^1.3.11",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0",
"is-mobile": "^5.0.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"moment": "^2.30.1",
"r": "^0.0.5",
"react": "^19.1.1", "react": "^19.1.1",
"react-calendar-timeline": "^0.30.0-beta.3",
"react-day-picker": "^9.11.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"socket.io-client": "^4.8.1",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",
@@ -527,6 +538,51 @@
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz", "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==" "integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
}, },
"node_modules/@date-fns/tz": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz",
"integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==",
"license": "MIT"
},
"node_modules/@dnd-kit/accessibility": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
"license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@dnd-kit/core": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
"license": "MIT",
"dependencies": {
"@dnd-kit/accessibility": "^3.1.1",
"@dnd-kit/utilities": "^3.2.2",
"tslib": "^2.0.0"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@dnd-kit/utilities": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9", "version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
@@ -1207,6 +1263,13 @@
"url": "https://github.com/sponsors/nzakas" "url": "https://github.com/sponsors/nzakas"
} }
}, },
"node_modules/@interactjs/types": {
"version": "1.10.27",
"resolved": "https://registry.npmjs.org/@interactjs/types/-/types-1.10.27.tgz",
"integrity": "sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA==",
"license": "MIT",
"peer": true
},
"node_modules/@isaacs/fs-minipass": { "node_modules/@isaacs/fs-minipass": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
@@ -1864,6 +1927,43 @@
} }
} }
}, },
"node_modules/@radix-ui/react-popover": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
"integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-dismissable-layer": "1.1.11",
"@radix-ui/react-focus-guards": "1.1.3",
"@radix-ui/react-focus-scope": "1.1.7",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-popper": "1.2.8",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-presence": "1.1.5",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-use-controllable-state": "1.2.2",
"aria-hidden": "^1.2.4",
"react-remove-scroll": "^2.6.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": { "node_modules/@radix-ui/react-popper": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
@@ -1998,6 +2098,37 @@
} }
} }
}, },
"node_modules/@radix-ui/react-scroll-area": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz",
"integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==",
"license": "MIT",
"dependencies": {
"@radix-ui/number": "1.1.1",
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-direction": "1.1.1",
"@radix-ui/react-presence": "1.1.5",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-use-callback-ref": "1.1.1",
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-select": { "node_modules/@radix-ui/react-select": {
"version": "2.2.6", "version": "2.2.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
@@ -2591,6 +2722,12 @@
"node": ">=20.0.0" "node": ">=20.0.0"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@swc/core": { "node_modules/@swc/core": {
"version": "1.13.5", "version": "1.13.5",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz",
@@ -3444,12 +3581,21 @@
"version": "19.1.11", "version": "19.1.11",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz",
"integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==", "integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==",
"devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/react-calendar-timeline": {
"version": "0.28.6",
"resolved": "https://registry.npmjs.org/@types/react-calendar-timeline/-/react-calendar-timeline-0.28.6.tgz",
"integrity": "sha512-43ttmxoxfi9IdMBjU+My8Aa5ArX0fq2DCOJSol6Bt/fbRKHS/fEmIP/GGeXYavpt+vmCjeToHHLPTw/EXqqAFQ==",
"license": "MIT",
"dependencies": {
"@types/react": "*",
"moment": "^2.0.0"
}
},
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "19.1.8", "version": "19.1.8",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.8.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.8.tgz",
@@ -3898,6 +4044,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/batch-processor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz",
"integrity": "sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==",
"license": "MIT"
},
"node_modules/better-auth": { "node_modules/better-auth": {
"version": "1.3.11", "version": "1.3.11",
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.3.11.tgz", "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.3.11.tgz",
@@ -4165,6 +4317,12 @@
"url": "https://polar.sh/cva" "url": "https://polar.sh/cva"
} }
}, },
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
"license": "MIT"
},
"node_modules/clsx": { "node_modules/clsx": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -4247,6 +4405,29 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/date-fns-jalali": {
"version": "4.1.0-0",
"resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz",
"integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==",
"license": "MIT"
},
"node_modules/dayjs": {
"version": "1.11.18",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
"license": "MIT",
"peer": true
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@@ -4345,6 +4526,54 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/element-resize-detector": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz",
"integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==",
"license": "MIT",
"dependencies": {
"batch-processor": "1.0.0"
}
},
"node_modules/engine.io-client": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-client/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.18.3", "version": "5.18.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
@@ -5058,6 +5287,16 @@
"node": ">=0.8.19" "node": ">=0.8.19"
} }
}, },
"node_modules/interactjs": {
"version": "1.10.27",
"resolved": "https://registry.npmjs.org/interactjs/-/interactjs-1.10.27.tgz",
"integrity": "sha512-y/8RcCftGAF24gSp76X2JS3XpHiUvDQyhF8i7ujemBz77hwiHDuJzftHx7thY8cxGogwGiPJ+o97kWB6eAXnsA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@interactjs/types": "1.10.27"
}
},
"node_modules/is-binary-path": { "node_modules/is-binary-path": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -5094,6 +5333,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/is-mobile": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-5.0.0.tgz",
"integrity": "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==",
"license": "MIT"
},
"node_modules/is-number": { "node_modules/is-number": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -5491,6 +5736,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -5535,6 +5786,12 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/merge2": { "node_modules/merge2": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5629,11 +5886,19 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
@@ -5904,6 +6169,14 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/r": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/r/-/r-0.0.5.tgz",
"integrity": "sha512-rO+FXCKIUiLEVCP4HjIEkq8V5gRHc1N15/2K97GSOE/P5evYj6uOOgvHlINCwMHnEmHouBdeR6PBDzZDqmEH2A==",
"engines": {
"node": "*"
}
},
"node_modules/react": { "node_modules/react": {
"version": "19.1.1", "version": "19.1.1",
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
@@ -5913,6 +6186,45 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-calendar-timeline": {
"version": "0.30.0-beta.3",
"resolved": "https://registry.npmjs.org/react-calendar-timeline/-/react-calendar-timeline-0.30.0-beta.3.tgz",
"integrity": "sha512-TckfoAzJvK5FEQo83vejbVtSDX1XNxcFmfCq92lMZKQiEuzbk7adcQi+ySlL9uSZ1ulFZS6YMAS6rzEGsVtZ2A==",
"license": "MIT",
"dependencies": {
"classnames": "^2.5.1",
"element-resize-detector": "^1.2.4",
"lodash": "^4.17.21",
"memoize-one": "^6.0.0"
},
"peerDependencies": {
"dayjs": ">=1.10.0",
"interactjs": "1.10.27",
"react": "^18 || ^19.0.0-rc-66855b96-20241106",
"react-dom": "^18 || ^19.0.0-rc-66855b96-20241106"
}
},
"node_modules/react-day-picker": {
"version": "9.11.1",
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.11.1.tgz",
"integrity": "sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==",
"license": "MIT",
"dependencies": {
"@date-fns/tz": "^1.4.1",
"date-fns": "^4.1.0",
"date-fns-jalali": "^4.1.0-0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/gpbl"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "19.1.1", "version": "19.1.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
@@ -6209,6 +6521,68 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/socket.io-client": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.6.1",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-client/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/solid-js": { "node_modules/solid-js": {
"version": "1.9.9", "version": "1.9.9",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz",
@@ -6802,6 +7176,35 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",

View File

@@ -10,11 +10,14 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1",
"@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.7", "@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-slot": "^1.2.3",
@@ -24,14 +27,22 @@
"@tanstack/react-query": "^5.89.0", "@tanstack/react-query": "^5.89.0",
"@tanstack/react-router": "^1.131.36", "@tanstack/react-router": "^1.131.36",
"@tanstack/react-router-devtools": "^1.131.36", "@tanstack/react-router-devtools": "^1.131.36",
"@types/react-calendar-timeline": "^0.28.6",
"axios": "^1.12.2", "axios": "^1.12.2",
"better-auth": "^1.3.11", "better-auth": "^1.3.11",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0",
"is-mobile": "^5.0.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"moment": "^2.30.1",
"r": "^0.0.5",
"react": "^19.1.1", "react": "^19.1.1",
"react-calendar-timeline": "^0.30.0-beta.3",
"react-day-picker": "^9.11.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"socket.io-client": "^4.8.1",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",

View File

@@ -0,0 +1,225 @@
import * as React from "react";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react";
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
import { buttonVariants, Button } from "./button";
import { cn } from "../../lib/utils";
function Calendar({
className,
classNames,
showOutsideDays = true,
captionLayout = "label",
buttonVariant = "ghost",
formatters,
components,
...props
}: React.ComponentProps<typeof DayPicker> & {
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
}) {
const defaultClassNames = getDefaultClassNames();
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn(
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
className
)}
captionLayout={captionLayout}
formatters={{
formatMonthDropdown: (date) =>
date.toLocaleString("default", { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
months: cn(
"flex gap-4 flex-col md:flex-row relative",
defaultClassNames.months
),
month: cn(
"flex flex-col w-full gap-4",
defaultClassNames.month
),
nav: cn(
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
defaultClassNames.nav
),
button_previous: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_previous
),
button_next: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_next
),
month_caption: cn(
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
defaultClassNames.month_caption
),
dropdowns: cn(
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
defaultClassNames.dropdowns
),
dropdown_root: cn(
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
defaultClassNames.dropdown_root
),
dropdown: cn(
"absolute bg-popover inset-0 opacity-0",
defaultClassNames.dropdown
),
caption_label: cn(
"select-none font-medium",
captionLayout === "label"
? "text-sm"
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
defaultClassNames.caption_label
),
table: "w-full border-collapse",
weekdays: cn("flex", defaultClassNames.weekdays),
weekday: cn(
"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
defaultClassNames.weekday
),
week: cn("flex w-full mt-2", defaultClassNames.week),
week_number_header: cn(
"select-none w-(--cell-size)",
defaultClassNames.week_number_header
),
week_number: cn(
"text-[0.8rem] select-none text-muted-foreground",
defaultClassNames.week_number
),
day: cn(
"relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
defaultClassNames.day
),
range_start: cn(
"rounded-l-md bg-accent",
defaultClassNames.range_start
),
range_middle: cn(
"rounded-none",
defaultClassNames.range_middle
),
range_end: cn(
"rounded-r-md bg-accent",
defaultClassNames.range_end
),
today: cn(
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
defaultClassNames.today
),
outside: cn(
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside
),
disabled: cn(
"text-muted-foreground opacity-50",
defaultClassNames.disabled
),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
Root: ({ className, rootRef, ...props }) => {
return (
<div
data-slot="calendar"
ref={rootRef}
className={cn(className)}
{...props}
/>
);
},
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
<ChevronLeftIcon
className={cn("size-4", className)}
{...props}
/>
);
}
if (orientation === "right") {
return (
<ChevronRightIcon
className={cn("size-4", className)}
{...props}
/>
);
}
return (
<ChevronDownIcon
className={cn("size-4", className)}
{...props}
/>
);
},
DayButton: CalendarDayButton,
WeekNumber: ({ children, ...props }) => {
return (
<td {...props}>
<div className="flex size-(--cell-size) items-center justify-center text-center">
{children}
</div>
</td>
);
},
...components,
}}
{...props}
/>
);
}
function CalendarDayButton({
className,
day,
modifiers,
...props
}: React.ComponentProps<typeof DayButton>) {
const defaultClassNames = getDefaultClassNames();
const ref = React.useRef<HTMLButtonElement>(null);
React.useEffect(() => {
if (modifiers.focused) ref.current?.focus();
}, [modifiers.focused]);
return (
<Button
ref={ref}
variant="ghost"
size="icon"
data-day={day.date.toLocaleDateString()}
data-selected-single={
modifiers.selected &&
!modifiers.range_start &&
!modifiers.range_end &&
!modifiers.range_middle
}
data-range-start={modifiers.range_start}
data-range-end={modifiers.range_end}
data-range-middle={modifiers.range_middle}
className={cn(
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
defaultClassNames.day,
className
)}
{...props}
/>
);
}
export { Calendar, CalendarDayButton };

View File

@@ -0,0 +1,31 @@
import { format } from "date-fns";
import { Calendar as CalendarIcon } from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
import { Button } from "./button";
import { Calendar } from "./calendar";
export function DatePicker({
date,
onChange,
}: {
date?: Date;
onChange?: (d: Date | undefined) => void;
}) {
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
data-empty={!date}
className="data-[empty=true]:text-muted-foreground w-[200px] justify-start text-left font-normal"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar mode="single" selected={date} onSelect={onChange} />
</PopoverContent>
</Popover>
);
}

View File

@@ -0,0 +1,45 @@
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "../../lib/utils";
function Popover({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
}
function PopoverTrigger({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
}
function PopoverContent({
className,
align = "center",
sideOffset = 4,
...props
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
data-slot="popover-content"
align={align}
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
);
}
function PopoverAnchor({
...props
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
}
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };

View File

@@ -0,0 +1,56 @@
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import { cn } from "@/lib/utils"
function ScrollArea({
className,
children,
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn("relative", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
)
}
function ScrollBar({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
return (
<ScrollAreaPrimitive.ScrollAreaScrollbar
data-slot="scroll-area-scrollbar"
orientation={orientation}
className={cn(
"flex touch-none p-px transition-colors select-none",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb
data-slot="scroll-area-thumb"
className="bg-border relative flex-1 rounded-full"
/>
</ScrollAreaPrimitive.ScrollAreaScrollbar>
)
}
export { ScrollArea, ScrollBar }

View File

@@ -0,0 +1,59 @@
import { io } from "socket.io-client";
export const coreSocket = io(
window.location.origin || "http://localhost:3000",
{
path: "/lst/api/ws",
autoConnect: true,
// transports: ["websocket", "polling"],
withCredentials: true,
reconnectionAttempts: 5,
timeout: 10_000,
}
);
// --- Core events ---
coreSocket.on("connect", () => {
console.log("✅ Core connected:", coreSocket.id);
console.log("🔗 Transport:", coreSocket.io.engine.transport.name);
});
coreSocket.on("disconnect", (reason) => {
console.warn("🔴 Core disconnected:", reason);
if (reason === "io server disconnect") coreSocket.connect();
});
coreSocket.on("connect_error", (err) => {
console.error("❌ Core connect error:", err.message);
});
coreSocket.io.on("reconnect_attempt", (attempt) => {
console.log("♻️ Core reconnect attempt:", attempt);
});
coreSocket.io.on("reconnect_failed", () => {
console.error("💀 Core reconnect failed after max attempts");
});
coreSocket.io.engine.on("upgrade", (transport) => {
console.log("🚀 Core upgraded to:", transport.name);
});
coreSocket.io.engine.on("close", (reason) => {
console.warn("🧨 Core engine closed:", reason);
});
setInterval(() => {
//console.log(window.location.origin);
if (coreSocket.connected) {
coreSocket.emit("keepalive");
console.log("🏓 Ping sent to server");
} else {
//console.warn("⚠️ Socket not connected, skipping ping");
}
}, 30 * 1000);
// Optional: listen for server acknowledgment
coreSocket.on("pongCheck", (data) => {
console.log("🏓 Pong received from server:", data);
});

View File

@@ -14,16 +14,27 @@ import { Route as rootRouteImport } from './routes/__root'
import { Route as AdminLayoutRouteRouteImport } from './routes/_adminLayout/route' import { Route as AdminLayoutRouteRouteImport } from './routes/_adminLayout/route'
import { Route as IndexRouteImport } from './routes/index' import { Route as IndexRouteImport } from './routes/index'
import { Route as authLoginRouteImport } from './routes/(auth)/login' import { Route as authLoginRouteImport } from './routes/(auth)/login'
import { Route as mobileStuffMobileLayoutRouteRouteImport } from './routes/(mobileStuff)/_mobileLayout/route'
import { Route as AdminLayoutAdminSettingsRouteImport } from './routes/_adminLayout/admin/settings' import { Route as AdminLayoutAdminSettingsRouteImport } from './routes/_adminLayout/admin/settings'
import { Route as AdminLayoutAdminServersRouteImport } from './routes/_adminLayout/admin/servers' import { Route as AdminLayoutAdminServersRouteImport } from './routes/_adminLayout/admin/servers'
import { Route as logisticsLogisticsDeliveryScheduleRouteImport } from './routes/(logistics)/logistics/deliverySchedule'
import { Route as authUserSignupRouteImport } from './routes/(auth)/user/signup' import { Route as authUserSignupRouteImport } from './routes/(auth)/user/signup'
import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user/resetpassword' import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user/resetpassword'
import { Route as AdminLayoutAdminUsersRouteRouteImport } from './routes/_adminLayout/admin/_users/route' import { Route as AdminLayoutAdminUsersRouteRouteImport } from './routes/_adminLayout/admin/_users/route'
import { Route as mobileStuffMobileLayoutMIndexRouteImport } from './routes/(mobileStuff)/_mobileLayout/m/index'
import { Route as AdminLayoutAdminUsersUsersRouteImport } from './routes/_adminLayout/admin/_users/users' import { Route as AdminLayoutAdminUsersUsersRouteImport } from './routes/_adminLayout/admin/_users/users'
import { Route as AdminLayoutAdminUsersProdUsersRouteImport } from './routes/_adminLayout/admin/_users/prodUsers' import { Route as AdminLayoutAdminUsersProdUsersRouteImport } from './routes/_adminLayout/admin/_users/prodUsers'
import { Route as mobileStuffMobileLayoutMRelocateRouteImport } from './routes/(mobileStuff)/_mobileLayout/m/relocate'
import { Route as mobileStuffMobileLayoutMDeliveryRouteImport } from './routes/(mobileStuff)/_mobileLayout/m/delivery'
import { Route as mobileStuffMobileLayoutMCyclecountsRouteImport } from './routes/(mobileStuff)/_mobileLayout/m/cyclecounts'
const mobileStuffRouteImport = createFileRoute('/(mobileStuff)')()
const AdminLayoutAdminRouteImport = createFileRoute('/_adminLayout/admin')() const AdminLayoutAdminRouteImport = createFileRoute('/_adminLayout/admin')()
const mobileStuffRoute = mobileStuffRouteImport.update({
id: '/(mobileStuff)',
getParentRoute: () => rootRouteImport,
} as any)
const AdminLayoutRouteRoute = AdminLayoutRouteRouteImport.update({ const AdminLayoutRouteRoute = AdminLayoutRouteRouteImport.update({
id: '/_adminLayout', id: '/_adminLayout',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
@@ -43,6 +54,11 @@ const authLoginRoute = authLoginRouteImport.update({
path: '/login', path: '/login',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const mobileStuffMobileLayoutRouteRoute =
mobileStuffMobileLayoutRouteRouteImport.update({
id: '/_mobileLayout',
getParentRoute: () => mobileStuffRoute,
} as any)
const AdminLayoutAdminSettingsRoute = const AdminLayoutAdminSettingsRoute =
AdminLayoutAdminSettingsRouteImport.update({ AdminLayoutAdminSettingsRouteImport.update({
id: '/settings', id: '/settings',
@@ -54,6 +70,12 @@ const AdminLayoutAdminServersRoute = AdminLayoutAdminServersRouteImport.update({
path: '/servers', path: '/servers',
getParentRoute: () => AdminLayoutAdminRoute, getParentRoute: () => AdminLayoutAdminRoute,
} as any) } as any)
const logisticsLogisticsDeliveryScheduleRoute =
logisticsLogisticsDeliveryScheduleRouteImport.update({
id: '/(logistics)/logistics/deliverySchedule',
path: '/logistics/deliverySchedule',
getParentRoute: () => rootRouteImport,
} as any)
const authUserSignupRoute = authUserSignupRouteImport.update({ const authUserSignupRoute = authUserSignupRouteImport.update({
id: '/(auth)/user/signup', id: '/(auth)/user/signup',
path: '/user/signup', path: '/user/signup',
@@ -69,6 +91,12 @@ const AdminLayoutAdminUsersRouteRoute =
id: '/_users', id: '/_users',
getParentRoute: () => AdminLayoutAdminRoute, getParentRoute: () => AdminLayoutAdminRoute,
} as any) } as any)
const mobileStuffMobileLayoutMIndexRoute =
mobileStuffMobileLayoutMIndexRouteImport.update({
id: '/m/',
path: '/m/',
getParentRoute: () => mobileStuffMobileLayoutRouteRoute,
} as any)
const AdminLayoutAdminUsersUsersRoute = const AdminLayoutAdminUsersUsersRoute =
AdminLayoutAdminUsersUsersRouteImport.update({ AdminLayoutAdminUsersUsersRouteImport.update({
id: '/users', id: '/users',
@@ -81,42 +109,77 @@ const AdminLayoutAdminUsersProdUsersRoute =
path: '/prodUsers', path: '/prodUsers',
getParentRoute: () => AdminLayoutAdminUsersRouteRoute, getParentRoute: () => AdminLayoutAdminUsersRouteRoute,
} as any) } as any)
const mobileStuffMobileLayoutMRelocateRoute =
mobileStuffMobileLayoutMRelocateRouteImport.update({
id: '/m/relocate',
path: '/m/relocate',
getParentRoute: () => mobileStuffMobileLayoutRouteRoute,
} as any)
const mobileStuffMobileLayoutMDeliveryRoute =
mobileStuffMobileLayoutMDeliveryRouteImport.update({
id: '/m/delivery',
path: '/m/delivery',
getParentRoute: () => mobileStuffMobileLayoutRouteRoute,
} as any)
const mobileStuffMobileLayoutMCyclecountsRoute =
mobileStuffMobileLayoutMCyclecountsRouteImport.update({
id: '/m/cyclecounts',
path: '/m/cyclecounts',
getParentRoute: () => mobileStuffMobileLayoutRouteRoute,
} as any)
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof mobileStuffMobileLayoutRouteRouteWithChildren
'/login': typeof authLoginRoute '/login': typeof authLoginRoute
'/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren '/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/logistics/deliverySchedule': typeof logisticsLogisticsDeliveryScheduleRoute
'/admin/servers': typeof AdminLayoutAdminServersRoute '/admin/servers': typeof AdminLayoutAdminServersRoute
'/admin/settings': typeof AdminLayoutAdminSettingsRoute '/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/m/cyclecounts': typeof mobileStuffMobileLayoutMCyclecountsRoute
'/m/delivery': typeof mobileStuffMobileLayoutMDeliveryRoute
'/m/relocate': typeof mobileStuffMobileLayoutMRelocateRoute
'/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute '/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/admin/users': typeof AdminLayoutAdminUsersUsersRoute '/admin/users': typeof AdminLayoutAdminUsersUsersRoute
'/m': typeof mobileStuffMobileLayoutMIndexRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof mobileStuffMobileLayoutRouteRouteWithChildren
'/login': typeof authLoginRoute '/login': typeof authLoginRoute
'/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren '/admin': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/logistics/deliverySchedule': typeof logisticsLogisticsDeliveryScheduleRoute
'/admin/servers': typeof AdminLayoutAdminServersRoute '/admin/servers': typeof AdminLayoutAdminServersRoute
'/admin/settings': typeof AdminLayoutAdminSettingsRoute '/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/m/cyclecounts': typeof mobileStuffMobileLayoutMCyclecountsRoute
'/m/delivery': typeof mobileStuffMobileLayoutMDeliveryRoute
'/m/relocate': typeof mobileStuffMobileLayoutMRelocateRoute
'/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute '/admin/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/admin/users': typeof AdminLayoutAdminUsersUsersRoute '/admin/users': typeof AdminLayoutAdminUsersUsersRoute
'/m': typeof mobileStuffMobileLayoutMIndexRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRouteImport __root__: typeof rootRouteImport
'/': typeof IndexRoute '/': typeof IndexRoute
'/_adminLayout': typeof AdminLayoutRouteRouteWithChildren '/_adminLayout': typeof AdminLayoutRouteRouteWithChildren
'/(mobileStuff)': typeof mobileStuffRouteWithChildren
'/(mobileStuff)/_mobileLayout': typeof mobileStuffMobileLayoutRouteRouteWithChildren
'/(auth)/login': typeof authLoginRoute '/(auth)/login': typeof authLoginRoute
'/_adminLayout/admin': typeof AdminLayoutAdminRouteWithChildren '/_adminLayout/admin': typeof AdminLayoutAdminRouteWithChildren
'/_adminLayout/admin/_users': typeof AdminLayoutAdminUsersRouteRouteWithChildren '/_adminLayout/admin/_users': typeof AdminLayoutAdminUsersRouteRouteWithChildren
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute '/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
'/(auth)/user/signup': typeof authUserSignupRoute '/(auth)/user/signup': typeof authUserSignupRoute
'/(logistics)/logistics/deliverySchedule': typeof logisticsLogisticsDeliveryScheduleRoute
'/_adminLayout/admin/servers': typeof AdminLayoutAdminServersRoute '/_adminLayout/admin/servers': typeof AdminLayoutAdminServersRoute
'/_adminLayout/admin/settings': typeof AdminLayoutAdminSettingsRoute '/_adminLayout/admin/settings': typeof AdminLayoutAdminSettingsRoute
'/(mobileStuff)/_mobileLayout/m/cyclecounts': typeof mobileStuffMobileLayoutMCyclecountsRoute
'/(mobileStuff)/_mobileLayout/m/delivery': typeof mobileStuffMobileLayoutMDeliveryRoute
'/(mobileStuff)/_mobileLayout/m/relocate': typeof mobileStuffMobileLayoutMRelocateRoute
'/_adminLayout/admin/_users/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute '/_adminLayout/admin/_users/prodUsers': typeof AdminLayoutAdminUsersProdUsersRoute
'/_adminLayout/admin/_users/users': typeof AdminLayoutAdminUsersUsersRoute '/_adminLayout/admin/_users/users': typeof AdminLayoutAdminUsersUsersRoute
'/(mobileStuff)/_mobileLayout/m/': typeof mobileStuffMobileLayoutMIndexRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
@@ -126,10 +189,15 @@ export interface FileRouteTypes {
| '/admin' | '/admin'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/logistics/deliverySchedule'
| '/admin/servers' | '/admin/servers'
| '/admin/settings' | '/admin/settings'
| '/m/cyclecounts'
| '/m/delivery'
| '/m/relocate'
| '/admin/prodUsers' | '/admin/prodUsers'
| '/admin/users' | '/admin/users'
| '/m'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: to:
| '/' | '/'
@@ -137,35 +205,56 @@ export interface FileRouteTypes {
| '/admin' | '/admin'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/logistics/deliverySchedule'
| '/admin/servers' | '/admin/servers'
| '/admin/settings' | '/admin/settings'
| '/m/cyclecounts'
| '/m/delivery'
| '/m/relocate'
| '/admin/prodUsers' | '/admin/prodUsers'
| '/admin/users' | '/admin/users'
| '/m'
id: id:
| '__root__' | '__root__'
| '/' | '/'
| '/_adminLayout' | '/_adminLayout'
| '/(mobileStuff)'
| '/(mobileStuff)/_mobileLayout'
| '/(auth)/login' | '/(auth)/login'
| '/_adminLayout/admin' | '/_adminLayout/admin'
| '/_adminLayout/admin/_users' | '/_adminLayout/admin/_users'
| '/(auth)/user/resetpassword' | '/(auth)/user/resetpassword'
| '/(auth)/user/signup' | '/(auth)/user/signup'
| '/(logistics)/logistics/deliverySchedule'
| '/_adminLayout/admin/servers' | '/_adminLayout/admin/servers'
| '/_adminLayout/admin/settings' | '/_adminLayout/admin/settings'
| '/(mobileStuff)/_mobileLayout/m/cyclecounts'
| '/(mobileStuff)/_mobileLayout/m/delivery'
| '/(mobileStuff)/_mobileLayout/m/relocate'
| '/_adminLayout/admin/_users/prodUsers' | '/_adminLayout/admin/_users/prodUsers'
| '/_adminLayout/admin/_users/users' | '/_adminLayout/admin/_users/users'
| '/(mobileStuff)/_mobileLayout/m/'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
IndexRoute: typeof IndexRoute IndexRoute: typeof IndexRoute
AdminLayoutRouteRoute: typeof AdminLayoutRouteRouteWithChildren AdminLayoutRouteRoute: typeof AdminLayoutRouteRouteWithChildren
mobileStuffRoute: typeof mobileStuffRouteWithChildren
authLoginRoute: typeof authLoginRoute authLoginRoute: typeof authLoginRoute
authUserResetpasswordRoute: typeof authUserResetpasswordRoute authUserResetpasswordRoute: typeof authUserResetpasswordRoute
authUserSignupRoute: typeof authUserSignupRoute authUserSignupRoute: typeof authUserSignupRoute
logisticsLogisticsDeliveryScheduleRoute: typeof logisticsLogisticsDeliveryScheduleRoute
} }
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
interface FileRoutesByPath { interface FileRoutesByPath {
'/(mobileStuff)': {
id: '/(mobileStuff)'
path: '/'
fullPath: '/'
preLoaderRoute: typeof mobileStuffRouteImport
parentRoute: typeof rootRouteImport
}
'/_adminLayout': { '/_adminLayout': {
id: '/_adminLayout' id: '/_adminLayout'
path: '' path: ''
@@ -194,6 +283,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof authLoginRouteImport preLoaderRoute: typeof authLoginRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/(mobileStuff)/_mobileLayout': {
id: '/(mobileStuff)/_mobileLayout'
path: '/'
fullPath: '/'
preLoaderRoute: typeof mobileStuffMobileLayoutRouteRouteImport
parentRoute: typeof mobileStuffRoute
}
'/_adminLayout/admin/settings': { '/_adminLayout/admin/settings': {
id: '/_adminLayout/admin/settings' id: '/_adminLayout/admin/settings'
path: '/settings' path: '/settings'
@@ -208,6 +304,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AdminLayoutAdminServersRouteImport preLoaderRoute: typeof AdminLayoutAdminServersRouteImport
parentRoute: typeof AdminLayoutAdminRoute parentRoute: typeof AdminLayoutAdminRoute
} }
'/(logistics)/logistics/deliverySchedule': {
id: '/(logistics)/logistics/deliverySchedule'
path: '/logistics/deliverySchedule'
fullPath: '/logistics/deliverySchedule'
preLoaderRoute: typeof logisticsLogisticsDeliveryScheduleRouteImport
parentRoute: typeof rootRouteImport
}
'/(auth)/user/signup': { '/(auth)/user/signup': {
id: '/(auth)/user/signup' id: '/(auth)/user/signup'
path: '/user/signup' path: '/user/signup'
@@ -229,6 +332,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AdminLayoutAdminUsersRouteRouteImport preLoaderRoute: typeof AdminLayoutAdminUsersRouteRouteImport
parentRoute: typeof AdminLayoutAdminRoute parentRoute: typeof AdminLayoutAdminRoute
} }
'/(mobileStuff)/_mobileLayout/m/': {
id: '/(mobileStuff)/_mobileLayout/m/'
path: '/m'
fullPath: '/m'
preLoaderRoute: typeof mobileStuffMobileLayoutMIndexRouteImport
parentRoute: typeof mobileStuffMobileLayoutRouteRoute
}
'/_adminLayout/admin/_users/users': { '/_adminLayout/admin/_users/users': {
id: '/_adminLayout/admin/_users/users' id: '/_adminLayout/admin/_users/users'
path: '/users' path: '/users'
@@ -243,6 +353,27 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AdminLayoutAdminUsersProdUsersRouteImport preLoaderRoute: typeof AdminLayoutAdminUsersProdUsersRouteImport
parentRoute: typeof AdminLayoutAdminUsersRouteRoute parentRoute: typeof AdminLayoutAdminUsersRouteRoute
} }
'/(mobileStuff)/_mobileLayout/m/relocate': {
id: '/(mobileStuff)/_mobileLayout/m/relocate'
path: '/m/relocate'
fullPath: '/m/relocate'
preLoaderRoute: typeof mobileStuffMobileLayoutMRelocateRouteImport
parentRoute: typeof mobileStuffMobileLayoutRouteRoute
}
'/(mobileStuff)/_mobileLayout/m/delivery': {
id: '/(mobileStuff)/_mobileLayout/m/delivery'
path: '/m/delivery'
fullPath: '/m/delivery'
preLoaderRoute: typeof mobileStuffMobileLayoutMDeliveryRouteImport
parentRoute: typeof mobileStuffMobileLayoutRouteRoute
}
'/(mobileStuff)/_mobileLayout/m/cyclecounts': {
id: '/(mobileStuff)/_mobileLayout/m/cyclecounts'
path: '/m/cyclecounts'
fullPath: '/m/cyclecounts'
preLoaderRoute: typeof mobileStuffMobileLayoutMCyclecountsRouteImport
parentRoute: typeof mobileStuffMobileLayoutRouteRoute
}
} }
} }
@@ -288,12 +419,51 @@ const AdminLayoutRouteRouteChildren: AdminLayoutRouteRouteChildren = {
const AdminLayoutRouteRouteWithChildren = const AdminLayoutRouteRouteWithChildren =
AdminLayoutRouteRoute._addFileChildren(AdminLayoutRouteRouteChildren) AdminLayoutRouteRoute._addFileChildren(AdminLayoutRouteRouteChildren)
interface mobileStuffMobileLayoutRouteRouteChildren {
mobileStuffMobileLayoutMCyclecountsRoute: typeof mobileStuffMobileLayoutMCyclecountsRoute
mobileStuffMobileLayoutMDeliveryRoute: typeof mobileStuffMobileLayoutMDeliveryRoute
mobileStuffMobileLayoutMRelocateRoute: typeof mobileStuffMobileLayoutMRelocateRoute
mobileStuffMobileLayoutMIndexRoute: typeof mobileStuffMobileLayoutMIndexRoute
}
const mobileStuffMobileLayoutRouteRouteChildren: mobileStuffMobileLayoutRouteRouteChildren =
{
mobileStuffMobileLayoutMCyclecountsRoute:
mobileStuffMobileLayoutMCyclecountsRoute,
mobileStuffMobileLayoutMDeliveryRoute:
mobileStuffMobileLayoutMDeliveryRoute,
mobileStuffMobileLayoutMRelocateRoute:
mobileStuffMobileLayoutMRelocateRoute,
mobileStuffMobileLayoutMIndexRoute: mobileStuffMobileLayoutMIndexRoute,
}
const mobileStuffMobileLayoutRouteRouteWithChildren =
mobileStuffMobileLayoutRouteRoute._addFileChildren(
mobileStuffMobileLayoutRouteRouteChildren,
)
interface mobileStuffRouteChildren {
mobileStuffMobileLayoutRouteRoute: typeof mobileStuffMobileLayoutRouteRouteWithChildren
}
const mobileStuffRouteChildren: mobileStuffRouteChildren = {
mobileStuffMobileLayoutRouteRoute:
mobileStuffMobileLayoutRouteRouteWithChildren,
}
const mobileStuffRouteWithChildren = mobileStuffRoute._addFileChildren(
mobileStuffRouteChildren,
)
const rootRouteChildren: RootRouteChildren = { const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute, IndexRoute: IndexRoute,
AdminLayoutRouteRoute: AdminLayoutRouteRouteWithChildren, AdminLayoutRouteRoute: AdminLayoutRouteRouteWithChildren,
mobileStuffRoute: mobileStuffRouteWithChildren,
authLoginRoute: authLoginRoute, authLoginRoute: authLoginRoute,
authUserResetpasswordRoute: authUserResetpasswordRoute, authUserResetpasswordRoute: authUserResetpasswordRoute,
authUserSignupRoute: authUserSignupRoute, authUserSignupRoute: authUserSignupRoute,
logisticsLogisticsDeliveryScheduleRoute:
logisticsLogisticsDeliveryScheduleRoute,
} }
export const routeTree = rootRouteImport export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren) ._addFileChildren(rootRouteChildren)

View File

@@ -0,0 +1,24 @@
// src/routes/traffic/DropCell.tsx
import { useDroppable } from "@dnd-kit/core";
export function DropCell({ day, hour, children }: any) {
const { setNodeRef, isOver } = useDroppable({
id: `${day.toDateString()}-${hour}`,
data: { day, hour },
});
return (
<div
ref={setNodeRef}
className={`relative border h-20 p-1 ${
isOver ? "bg-blue-400" : ""
} overflow-visible`}
style={{
maxWidth: 340, // your allotted width
alignContent: "flex-start",
}}
>
{children}
</div>
);
}

View File

@@ -0,0 +1,69 @@
// src/routes/traffic/Grid.tsx
import { format } from "date-fns";
import React from "react";
import { ScrollArea, ScrollBar } from "../../../components/ui/scroll-area";
export const days = Array.from(
{ length: 5 },
(_, i) => new Date(Date.now() + i * 24 * 60 * 60 * 1000),
);
// the layout of the hours
const hoursBefore = 3;
const totalHours = 24;
// get the current hour
const currentHour = new Date().getHours();
const startHour = (currentHour - hoursBefore + 24) % 24;
// generate the hours array
const hours = Array.from(
{ length: totalHours },
(_, i) => (startHour + i) % 24,
);
export function Grid({
days,
children,
}: {
days: any;
children?: (day: Date, hour: number) => React.ReactNode;
}) {
return (
<ScrollArea className={`h-[80vh]`}>
<div
className="grid"
style={{
display: "grid",
gridTemplateColumns: `100px repeat(${days.length}, 350px)`, // each day = 180px wide
//minWidth: `${100 + days.length * 350}px`,
}}
>
{/* Empty top-left corner */}
<div className="sticky top-0 left-0 bg-background z-30"></div>
{/* Date headers */}
{days.map((d: any) => (
<div
key={d.toDateString()}
className="sticky top-0 bg-background z-20 p-2 font-semibold text-center"
>
{format(d, "EEEE M/d/yyyy")}
</div>
))}
{hours.map((hour) => (
<React.Fragment key={hour}>
<div className="border p-1 text-right text-sm">{hour}:00</div>
{days.map((d: any) => (
<div key={`${d}-${hour}`} className="relative border h-20">
{children && children(d, hour)}
</div>
))}
</React.Fragment>
))}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
);
}

View File

@@ -0,0 +1,34 @@
import React from "react";
// GridBody.tsx
export function GridBody({ days, children }: { days: Date[]; children: any }) {
const hours = Array.from({ length: 24 }, (_, i) => i);
return (
<div
className="grid overflow-x-auto"
style={{
display: "grid",
gridTemplateColumns: `100px repeat(${days.length},340px)`,
}}
>
{hours.map((hour) => (
<React.Fragment key={hour}>
{/* time label, sticky left */}
<div className="sticky left-0 bg-background border p-1 text-right text-sm z-10">
{hour}:00
</div>
{days.map((day) => (
<div
key={`${day}-${hour}`}
className="border h-20 relative"
>
{children && children(day, hour)}
</div>
))}
</React.Fragment>
))}
</div>
);
}

View File

@@ -0,0 +1,24 @@
// GridHeader.tsx
import { format } from "date-fns";
export function GridHeader({ days }: { days: Date[] }) {
return (
<div
className="grid sticky top-0 z-30 bg-background"
style={{
display: "grid",
gridTemplateColumns: `100px repeat(${days.length},340px)`,
}}
>
<div /> {/* Empty corner for time labels */}
{days.map((d) => (
<div
key={d.toDateString()}
className="p-2 font-semibold text-center border-b"
>
{format(d, "EEE M/d/yyyy")}
</div>
))}
</div>
);
}

View File

@@ -0,0 +1,44 @@
// ShipmentItem.tsx
import { useDraggable } from "@dnd-kit/core";
interface ShipmentItemProps {
shipment: any;
index?: number;
perm?: boolean;
}
export function ShipmentItem({
shipment,
index = 0,
perm = true,
}: ShipmentItemProps) {
const { setNodeRef, listeners, attributes, transform } = useDraggable({
id: shipment.orderNumber,
data: shipment,
});
const offsetX = index * 10;
const style: React.CSSProperties = {
transform: transform
? `translate(${transform.x}px, ${transform.y}px)`
: `translateX(${offsetX}px)`,
transition: transform ? "none" : "transform 0.2s ease",
zIndex: 10 + index,
position: "absolute",
top: 0,
left: 0,
cursor: "grab",
};
return (
<div
ref={setNodeRef}
{...listeners}
{...attributes}
style={style}
className="w-[160px] p-2 text-xs rounded shadow select-none "
>
{shipment.orderNumber}
</div>
);
}

View File

@@ -0,0 +1,125 @@
.react-calendar-timeline * {
box-sizing: border-box;
}
.react-calendar-timeline .rct-outer {
display: block;
overflow: hidden;
white-space: nowrap;
}
.react-calendar-timeline .rct-scroll {
display: inline-block;
white-space: normal;
vertical-align: top;
overflow-x: scroll;
overflow-y: hidden;
-ms-touch-action: none;
touch-action: none;
}
.react-calendar-timeline .rct-item:hover {
z-index: 88;
}
.react-calendar-timeline .rct-item .rct-item-content {
position: sticky;
position: -webkit-sticky; /* still fine — helps with drag display */
left: 0;
/* Let multiple lines render */
display: block;
white-space: normal; /* ⬅ allow wrapping */
overflow: visible; /* ⬅ don't clip longer content */
height: auto; /* ⬅ expand with content */
padding: 4px 6px; /* ⬅ spacing inside item */
line-height: 1.3; /* ⬅ readable multi-line spacing */
border-radius: 2px;
box-sizing: border-box; /* consistent height/padding */
}
.react-calendar-timeline .rct-sidebar {
overflow: hidden;
white-space: normal;
display: inline-block;
vertical-align: top;
position: relative;
box-sizing: border-box;
border-right: 1px solid #bbb;
}
.react-calendar-timeline .rct-sidebar.rct-sidebar-right {
border-right: 0;
border-left: 1px solid #bbb;
}
.react-calendar-timeline .rct-sidebar .rct-sidebar-row {
padding: 0 4px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
box-sizing: border-box;
margin: 0;
border-bottom: 1px solid #bbb;
}
.react-calendar-timeline .rct-sidebar .rct-sidebar-row.rct-sidebar-row-odd {
background: #0000000d;
}
.react-calendar-timeline .rct-sidebar .rct-sidebar-row.rct-sidebar-row-even {
background: transparent;
}
.react-calendar-timeline .rct-vertical-lines .rct-vl {
position: absolute;
border-left: 1px solid #bbb;
z-index: 30;
}
.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-vl-first {
border-left-width: 2px;
}
.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-day-6,
.react-calendar-timeline .rct-vertical-lines .rct-vl.rct-day-0 {
background: #faf6e180;
}
.react-calendar-timeline .rct-horizontal-lines {
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.react-calendar-timeline .rct-horizontal-lines .rct-hl-even,
.react-calendar-timeline .rct-horizontal-lines .rct-hl-odd {
border-bottom: 1px solid #bbb;
box-sizing: border-box;
z-index: 40;
}
.react-calendar-timeline .rct-horizontal-lines .rct-hl-odd {
background: #0000000d;
}
.react-calendar-timeline .rct-horizontal-lines .rct-hl-even {
background: transparent;
}
.react-calendar-timeline .rct-cursor-line {
position: absolute;
width: 2px;
background: #2196f3;
z-index: 51;
}
.react-calendar-timeline .rct-dateHeader {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
border-bottom: 1px solid #bbb;
cursor: pointer;
font-size: 14px;
background-color: #f0f0f0;
border-left: 2px solid #bbb;
}
.react-calendar-timeline .rct-dateHeader-primary {
background-color: initial;
border-left: 1px solid #bbb;
border-right: 1px solid #bbb;
color: #fff;
}
.react-calendar-timeline .rct-header-root {
background: #c52020;
border-bottom: 1px solid #bbb;
}
.react-calendar-timeline .rct-calendar-header {
border: 1px solid #bbb;
}

View File

@@ -0,0 +1,35 @@
import { useMemo, useState } from "react";
export function useDateWindow(initialStart = new Date()) {
const [startDate, setStartDate] = useState(initialStart);
const [endDayCount, setEndDayCount] = useState<string>(
localStorage.getItem("endDayCount") || "5",
);
const [startDayCount, startEndDayCount] = useState<string>(
localStorage.getItem("startDayCount") || "0",
);
const days = useMemo(() => {
const startOffset = parseInt(startDayCount, 10);
const endOffset = parseInt(endDayCount, 10);
const start = new Date(startDate);
start.setDate(start.getDate() - startOffset);
return Array.from({ length: endOffset + startOffset + 1 }, (_, i) => {
const d = new Date(start);
d.setDate(start.getDate() + i);
return d;
});
}, [startDate, startDayCount, endDayCount]);
return {
days,
startDate,
setStartDate,
endDayCount,
setEndDayCount,
startDayCount,
startEndDayCount,
};
}

View File

@@ -0,0 +1,66 @@
import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { coreSocket } from "../../../lib/socket.io/socket";
import "../-components/style.css";
import moment from "moment";
import Timeline from "react-calendar-timeline";
export const Route = createFileRoute("/(logistics)/logistics/deliverySchedule")(
{
beforeLoad: async () => {
coreSocket.emit("joinScheduler", "scheduler");
// coreSocket.on("scheduler", (p) => {
// console.log(`[scheduler] received:`, p);
// });
},
component: RouteComponent,
},
);
function RouteComponent() {
// connect to the channel
const [shipments, setShipments] = useState([]) as any;
//const [perm] = useState(true); // will check this for sure with a user permissions
const [loaded, setLoaded] = useState(false);
// useEffect(() => {
// const handleConnect = () => {
// console.log("✅ Socket connected, joining scheduler");
// coreSocket.emit("joinScheduler");
// };
// coreSocket.on("connect", handleConnect);
// //const handler = (msg: any) => console.log("💓", msg);
// const onUpdate = (msg: any) => {
// console.log(msg.data);
// setShipments(() => {
// return msg.data.map((i: any) => ({
// id: i.schedule_id,
// title: i.orderNumber,
// group: i.dock === "" ? 1 : 1, // this will just toss everything here for now will go to the actual dock id later
// start_time: moment(parseISO(i.lstDateCheck)),
// end_time: moment(addHours(parseISO(i.lstDateCheck), 1)),
// data: i,
// }));
// });
// if (!loaded) setLoaded(true);
// };
// //coreSocket.on("data", onData);
// coreSocket.on("scheduler:update", onUpdate);
// return () => {
// // cleanup on unmount
// //coreSocket.off("data", onData);
// coreSocket.off("scheduler:update", onUpdate);
// coreSocket.off("connect", handleConnect);
// };
// }, []);
// if (shipments.length === 0) {
// return <div>Loading.....</div>;
// }
return <div className="p-4 "></div>;
}

View File

@@ -0,0 +1,11 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute(
'/(mobileStuff)/_mobileLayout/m/cyclecounts',
)({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/(mobileStuff)/_mobileLayout/m/cyclecounts"!</div>
}

View File

@@ -0,0 +1,11 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(mobileStuff)/_mobileLayout/m/delivery')(
{
component: RouteComponent,
},
)
function RouteComponent() {
return <div>Hello "/(mobileStuff)/_mobileLayout/m/delivery"!</div>
}

View File

@@ -0,0 +1,78 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { LstCard } from "../../../../components/ui/lstCard";
import {
CardContent,
CardHeader,
CardTitle,
} from "../../../../components/ui/card";
import { Button } from "../../../../components/ui/button";
import { cn } from "../../../../lib/utils";
export const Route = createFileRoute("/(mobileStuff)/_mobileLayout/m/")({
component: RouteComponent,
});
const commands = [
{
title: "Relocate",
description: "Moves a pallet from one location to another",
link: "/lst/app/m/relocate",
},
{
title: "Cycle Counts",
description: "Will do a cycle count on a specific lane",
link: "/lst/app/m/cyclecounts",
},
{
title: "Delivery",
description:
"Scan pallets to a delivery that has already been drag down in stock",
link: "/lst/app/m/delivery",
},
];
function RouteComponent() {
return (
<div className="p-3 space-y-3">
<LstCard>
<CardHeader>
<CardTitle className="flex justify-center">
Commands
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-wrap justify-center gap-3">
{commands.map((cmd) => {
return (
<Link
key={cmd.title}
to={cmd.link}
className="block"
>
<Button
variant="outline"
className={cn(
"flex flex-col justify-center items-center",
"w-36 h-28 p-3 text-center", // fixed width/height for uniform grid
"border-muted bg-background hover:bg-accent/40",
"transition-all active:scale-95"
)}
>
<span className="text-base font-semibold leading-tight">
{cmd.title}
</span>
{/* <div className="max-w-[75px]">
<span className="text-xs text-wrap">
{cmd.description}
</span>
</div> */}
</Button>
</Link>
);
})}
</div>
</CardContent>
</LstCard>
</div>
);
}

View File

@@ -0,0 +1,11 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(mobileStuff)/_mobileLayout/m/relocate')(
{
component: RouteComponent,
},
)
function RouteComponent() {
return <div>Hello "/(mobileStuff)/_mobileLayout/m/relocate"!</div>
}

View File

@@ -0,0 +1,13 @@
import { createFileRoute, Outlet } from "@tanstack/react-router";
export const Route = createFileRoute("/(mobileStuff)/_mobileLayout")({
component: RouteComponent,
});
function RouteComponent() {
return (
<div>
<Outlet />
</div>
);
}

View File

@@ -1,4 +1,8 @@
import { createRootRouteWithContext, Outlet } from "@tanstack/react-router"; import {
createRootRouteWithContext,
Outlet,
useRouter,
} from "@tanstack/react-router";
import type { QueryClient } from "@tanstack/react-query"; import type { QueryClient } from "@tanstack/react-query";
import { Toaster } from "sonner"; import { Toaster } from "sonner";
@@ -10,6 +14,9 @@ import { SidebarProvider } from "../components/ui/sidebar";
import SideBarNav from "../components/navBar/SideBarNav"; import SideBarNav from "../components/navBar/SideBarNav";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { userAccess } from "../lib/authClient"; import { userAccess } from "../lib/authClient";
import mobile from "is-mobile";
import { useEffect } from "react";
import { coreSocket } from "../lib/socket.io/socket";
interface RootRouteContext { interface RootRouteContext {
queryClient: QueryClient; queryClient: QueryClient;
@@ -21,6 +28,29 @@ interface RootRouteContext {
const RootLayout = () => { const RootLayout = () => {
//const { logout, login } = Route.useRouteContext(); //const { logout, login } = Route.useRouteContext();
const defaultOpen = Cookies.get("sidebar_state") === "true"; const defaultOpen = Cookies.get("sidebar_state") === "true";
const router = useRouter();
// console.log(mobile({ featureDetect: true, tablet: true }));
// if mobile lets move to the mobile section.
useEffect(() => {
if (mobile({ featureDetect: true, tablet: true })) {
router.navigate({ to: "/m" });
}
coreSocket.on("connect", () => {
console.log("✅ Connected:", coreSocket.id);
});
coreSocket.on("disconnect", () => {
console.log("🔴 Disconnected");
});
return () => {
coreSocket.off("connect");
coreSocket.off("disconnect");
};
}, []);
return ( return (
<div> <div>
<SessionGuard> <SessionGuard>

View File

@@ -5,7 +5,6 @@
{ "path": "./tsconfig.node.json" } { "path": "./tsconfig.node.json" }
], ],
"compilerOptions": { "compilerOptions": {
"baseUrl": ".",
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }

View File

@@ -36,6 +36,8 @@ export default defineConfig({
}, },
server: { server: {
port: 5500, port: 5500,
host: true,
allowedHosts: true,
proxy: { proxy: {
"/lst/api": { "/lst/api": {
target: `http://localhost:${Number( target: `http://localhost:${Number(

View File

@@ -1,11 +1,11 @@
import { format } from "date-fns-tz";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import { settings } from "../../../../database/schema/settings.js"; import { settings } from "../../../../database/schema/settings.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js"; import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { query } from "../../sqlServer/prodSqlServer.js"; import { query } from "../../sqlServer/prodSqlServer.js";
import { lastSalesPriceCheck } from "../../sqlServer/querys/eom/lastSalesprice.js";
import { consumptionCheck } from "../../sqlServer/querys/eom/consumptionCheck.js"; import { consumptionCheck } from "../../sqlServer/querys/eom/consumptionCheck.js";
import { format } from "date-fns-tz"; import { lastSalesPriceCheck } from "../../sqlServer/querys/eom/lastSalesprice.js";
type Consumption = { type Consumption = {
startDate: string; startDate: string;
@@ -19,10 +19,16 @@ export const getProductionConsumption = async (consumption: Consumption) => {
consumptionCheck consumptionCheck
.replace("[startDate]", consumption.startDate) .replace("[startDate]", consumption.startDate)
.replace("[endDate]", consumption.endDate), .replace("[endDate]", consumption.endDate),
"Last sales price" "Last sales price",
) ),
)) as any; )) as any;
console.log(
consumptionCheck
.replace("[startDate]", consumption.startDate)
.replace("[endDate]", consumption.endDate),
);
console.log(data.data.length);
if (error) { if (error) {
return { return {
success: false, success: false,
@@ -33,7 +39,7 @@ export const getProductionConsumption = async (consumption: Consumption) => {
if (consumption.includePlantToken) { if (consumption.includePlantToken) {
const { data: s, error: se } = (await tryCatch( const { data: s, error: se } = (await tryCatch(
db.select().from(settings).where(eq(settings.name, "plantToken")) db.select().from(settings).where(eq(settings.name, "plantToken")),
)) as any; )) as any;
if (se) { if (se) {

View File

@@ -97,34 +97,71 @@ app.Run(async (HttpContext context) =>
} }
// Handle WebSocket requests // Handle WebSocket requests
if (context.WebSockets.IsWebSocketRequest) // if (context.WebSockets.IsWebSocketRequest)
{ // {
// try
// {
// var backendUri = new UriBuilder(backendWsBase)
// {
// Path = context.Request.Path,
// Query = context.Request.QueryString.ToString()
// }.Uri;
// using var backendSocket = new ClientWebSocket();
// // Forward incoming headers
// foreach (var header in context.Request.Headers)
// {
// try { backendSocket.Options.SetRequestHeader(header.Key, header.Value); }
// catch { /* ignore headers WS client doesn't like */ }
// }
// await backendSocket.ConnectAsync(backendUri, context.RequestAborted);
// using var frontendSocket = await context.WebSockets.AcceptWebSocketAsync();
// var cts = new CancellationTokenSource();
// var forwardToBackend = ForwardWebSocketAsync(frontendSocket, backendSocket, cts.Token);
// var forwardToFrontend = ForwardWebSocketAsync(backendSocket, frontendSocket, cts.Token);
// await Task.WhenAny(forwardToBackend, forwardToFrontend);
// cts.Cancel();
// }
// catch (Exception ex)
// {
// LogToFile($"WebSocket proxy error: {ex.Message}");
// context.Response.StatusCode = (int)HttpStatusCode.BadGateway;
// await context.Response.WriteAsync($"WebSocket proxy error: {ex.Message}");
// }
// return;
// }
if (context.WebSockets.IsWebSocketRequest)
{
try try
{ {
// Accept the incoming client WebSocket
using var frontendSocket = await context.WebSockets.AcceptWebSocketAsync();
// Build the backend WebSocket URI
var backendUri = new UriBuilder(backendWsBase) var backendUri = new UriBuilder(backendWsBase)
{ {
Path = context.Request.Path, Path = context.Request.Path,
Query = context.Request.QueryString.ToString() Query = context.Request.QueryString.ToString()
}.Uri; }.Uri;
// Connect to the Node.js backend
using var backendSocket = new ClientWebSocket(); using var backendSocket = new ClientWebSocket();
// Forward incoming headers
foreach (var header in context.Request.Headers)
{
try { backendSocket.Options.SetRequestHeader(header.Key, header.Value); }
catch { /* ignore headers WS client doesn't like */ }
}
await backendSocket.ConnectAsync(backendUri, context.RequestAborted); await backendSocket.ConnectAsync(backendUri, context.RequestAborted);
using var frontendSocket = await context.WebSockets.AcceptWebSocketAsync(); // Forward frames both ways until one side closes
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
var forwardToBackend = ForwardWebSocketAsync(frontendSocket, backendSocket, cts.Token); var forwardToBackend = ForwardWebSocketAsync(frontendSocket, backendSocket, cts.Token);
var forwardToFrontend = ForwardWebSocketAsync(backendSocket, frontendSocket, cts.Token); var forwardToFrontend = ForwardWebSocketAsync(backendSocket, frontendSocket, cts.Token);
await Task.WhenAny(forwardToBackend, forwardToFrontend); await Task.WhenAny(forwardToBackend, forwardToFrontend);
// Cancel the other direction once one side closes
cts.Cancel(); cts.Cancel();
} }
catch (Exception ex) catch (Exception ex)
@@ -133,9 +170,9 @@ app.Run(async (HttpContext context) =>
context.Response.StatusCode = (int)HttpStatusCode.BadGateway; context.Response.StatusCode = (int)HttpStatusCode.BadGateway;
await context.Response.WriteAsync($"WebSocket proxy error: {ex.Message}"); await context.Response.WriteAsync($"WebSocket proxy error: {ex.Message}");
} }
return;
}
return;
}
// Otherwise: normal HTTP request // Otherwise: normal HTTP request
var client = context.RequestServices.GetRequiredService<IHttpClientFactory>().CreateClient(); var client = context.RequestServices.GetRequiredService<IHttpClientFactory>().CreateClient();
var targetUri = backendHttpBase + context.Request.Path + context.Request.QueryString; var targetUri = backendHttpBase + context.Request.Path + context.Request.QueryString;

View File

@@ -24,6 +24,6 @@
arguments=".\lstWrapper.dll" arguments=".\lstWrapper.dll"
stdoutLogEnabled="true" stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout" stdoutLogFile=".\logs\stdout"
hostingModel="inprocess" /> hostingModel="outofprocess" />
</system.webServer> </system.webServer>
</configuration> </configuration>

View File

@@ -0,0 +1,21 @@
CREATE TABLE "orderScheduler" (
"schedule_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"order_type" text NOT NULL,
"order_number" integer NOT NULL,
"header" text NOT NULL,
"line_item_number" text,
"customer_release_number" text,
"delivery_date" date NOT NULL,
"loading_date" date,
"order_qty" real NOT NULL,
"order_lu" real NOT NULL,
"delivered_qty" real DEFAULT 0,
"delivered_lu" real DEFAULT 0,
"remark" text,
"current_state" integer,
"lst_date_check" date,
"dock" text,
"order_from" text
);
--> statement-breakpoint
CREATE UNIQUE INDEX "orderNumber" ON "orderScheduler" USING btree ("order_number");

View File

@@ -0,0 +1,2 @@
ALTER TABLE "orderScheduler" ADD COLUMN "av" integer;--> statement-breakpoint
ALTER TABLE "orderScheduler" ADD COLUMN "decription" text;

View File

@@ -0,0 +1,2 @@
ALTER TABLE "orderScheduler" ADD COLUMN "add_date" date DEFAULT now();--> statement-breakpoint
ALTER TABLE "orderScheduler" ADD COLUMN "upd_date" date DEFAULT now();

View File

@@ -0,0 +1 @@
ALTER TABLE "orderScheduler" RENAME COLUMN "decription" TO "description";

View File

@@ -0,0 +1,2 @@
ALTER TABLE "orderScheduler" ADD COLUMN "customer_address_id" integer;--> statement-breakpoint
ALTER TABLE "orderScheduler" ADD COLUMN "customer_description" text;

View File

@@ -0,0 +1 @@
ALTER TABLE "orderScheduler" ADD COLUMN "created_as_EDI" boolean;

View File

@@ -0,0 +1,7 @@
ALTER TABLE "orderScheduler" ALTER COLUMN "delivery_date" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "loading_date" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "lst_date_check" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "add_date" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "add_date" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "upd_date" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "orderScheduler" ALTER COLUMN "upd_date" SET DEFAULT now();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -85,6 +85,55 @@
"when": 1759195276875, "when": 1759195276875,
"tag": "0011_careless_banshee", "tag": "0011_careless_banshee",
"breakpoints": true "breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1760374807920,
"tag": "0012_wise_cardiac",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1760377601945,
"tag": "0013_known_dragon_man",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1760388532973,
"tag": "0014_huge_mother_askani",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1760388593956,
"tag": "0015_swift_rattler",
"breakpoints": true
},
{
"idx": 16,
"version": "7",
"when": 1760444321051,
"tag": "0016_glorious_wolf_cub",
"breakpoints": true
},
{
"idx": 17,
"version": "7",
"when": 1760457733998,
"tag": "0017_previous_kate_bishop",
"breakpoints": true
},
{
"idx": 18,
"version": "7",
"when": 1760480733009,
"tag": "0018_aspiring_silver_samurai",
"breakpoints": true
} }
] ]
} }

658
package-lock.json generated
View File

@@ -9,42 +9,45 @@
"version": "1.5.0", "version": "1.5.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@dotenvx/dotenvx": "^1.49.0", "@dotenvx/dotenvx": "^1.51.0",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"axios": "^1.12.2", "axios": "^1.12.2",
"better-auth": "^1.3.9", "better-auth": "^1.3.27",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0", "date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.31.4", "drizzle-kit": "^0.31.5",
"drizzle-orm": "^0.44.5", "drizzle-orm": "^0.44.6",
"drizzle-zod": "^0.8.3", "drizzle-zod": "^0.8.3",
"express": "^5.1.0", "express": "^5.1.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"morgan": "^1.10.1", "morgan": "^1.10.1",
"mssql": "^11.0.1", "mssql": "^12.0.0",
"nodemailer": "^7.0.6", "nodemailer": "^7.0.9",
"nodemailer-express-handlebars": "^7.0.0", "nodemailer-express-handlebars": "^7.0.0",
"npm-check-updates": "^19.0.0",
"pg": "^8.16.3", "pg": "^8.16.3",
"pino": "^9.9.0", "pino": "^10.0.0",
"pino-pretty": "^13.1.1", "pino-pretty": "^13.1.2",
"postgres": "^3.4.7", "postgres": "^3.4.7",
"zod": "^4.1.5" "socket.io": "^4.8.1",
"zod": "^4.1.12"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.2.6",
"@types/express": "^5.0.3", "@types/express": "^5.0.3",
"@types/morgan": "^1.9.10", "@types/morgan": "^1.9.10",
"@types/mssql": "^9.1.7", "@types/mssql": "^9.1.8",
"@types/node": "^24.3.0", "@types/node": "^24.7.1",
"@types/nodemailer": "^7.0.1", "@types/nodemailer": "^7.0.2",
"@types/nodemailer-express-handlebars": "^4.0.5", "@types/nodemailer-express-handlebars": "^4.0.5",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"cz-conventional-changelog": "^3.3.0", "cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0", "standard-version": "^9.5.0",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"tsx": "^4.20.4", "tsx": "^4.20.6",
"typescript": "^5.9.2" "typescript": "^5.9.3"
} }
}, },
"node_modules/@aws-crypto/sha256-browser": { "node_modules/@aws-crypto/sha256-browser": {
@@ -1055,20 +1058,189 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@better-auth/utils": { "node_modules/@better-auth/core": {
"version": "0.2.6", "version": "1.3.27",
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.6.tgz", "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.3.27.tgz",
"integrity": "sha512-3y/vaL5Ox33dBwgJ6ub3OPkVqr6B5xL2kgxNHG8eHZuryLyG/4JSPGqjbdRSgjuy9kALUZYDFl+ORIAxlWMSuA==", "integrity": "sha512-3Sfdax6MQyronY+znx7bOsfQHI6m1SThvJWb0RDscFEAhfqLy95k1sl+/PgGyg0cwc2cUXoEiAOSqYdFYrg3vA==",
"license": "MIT",
"dependencies": { "dependencies": {
"uncrypto": "^0.1.3" "better-call": "1.0.19",
"zod": "^4.1.5"
} }
}, },
"node_modules/@better-auth/utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz",
"integrity": "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==",
"license": "MIT"
},
"node_modules/@better-fetch/fetch": { "node_modules/@better-fetch/fetch": {
"version": "1.1.18", "version": "1.1.18",
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz", "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==" "integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
}, },
"node_modules/@biomejs/biome": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.6.tgz",
"integrity": "sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==",
"dev": true,
"license": "MIT OR Apache-2.0",
"bin": {
"biome": "bin/biome"
},
"engines": {
"node": ">=14.21.3"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/biome"
},
"optionalDependencies": {
"@biomejs/cli-darwin-arm64": "2.2.6",
"@biomejs/cli-darwin-x64": "2.2.6",
"@biomejs/cli-linux-arm64": "2.2.6",
"@biomejs/cli-linux-arm64-musl": "2.2.6",
"@biomejs/cli-linux-x64": "2.2.6",
"@biomejs/cli-linux-x64-musl": "2.2.6",
"@biomejs/cli-win32-arm64": "2.2.6",
"@biomejs/cli-win32-x64": "2.2.6"
}
},
"node_modules/@biomejs/cli-darwin-arm64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.6.tgz",
"integrity": "sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-darwin-x64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.6.tgz",
"integrity": "sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-linux-arm64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.6.tgz",
"integrity": "sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-linux-arm64-musl": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.6.tgz",
"integrity": "sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-linux-x64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.6.tgz",
"integrity": "sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-linux-x64-musl": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.6.tgz",
"integrity": "sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-win32-arm64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.6.tgz",
"integrity": "sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@biomejs/cli-win32-x64": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.6.tgz",
"integrity": "sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT OR Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.21.3"
}
},
"node_modules/@commitlint/config-validator": { "node_modules/@commitlint/config-validator": {
"version": "19.8.1", "version": "19.8.1",
"resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz", "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz",
@@ -1192,9 +1364,9 @@
} }
}, },
"node_modules/@dotenvx/dotenvx": { "node_modules/@dotenvx/dotenvx": {
"version": "1.49.0", "version": "1.51.0",
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.49.0.tgz", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.51.0.tgz",
"integrity": "sha512-M1cyP6YstFQCjih54SAxCqHLMMi8QqV8tenpgGE48RTXWD7vfMYJiw/6xcCDpS2h28AcLpTsFCZA863Ge9yxzA==", "integrity": "sha512-CbMGzyOYSyFF7d4uaeYwO9gpSBzLTnMmSmTVpCZjvpJFV69qYbjYPpzNnCz1mb2wIvEhjWjRwQWuBzTO0jITww==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"commander": "^11.1.0", "commander": "^11.1.0",
@@ -3007,6 +3179,12 @@
"node": ">=18.0.0" "node": ">=18.0.0"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@tanstack/react-table": { "node_modules/@tanstack/react-table": {
"version": "8.21.3", "version": "8.21.3",
"resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz",
@@ -3041,9 +3219,9 @@
} }
}, },
"node_modules/@tediousjs/connection-string": { "node_modules/@tediousjs/connection-string": {
"version": "0.5.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz", "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.6.0.tgz",
"integrity": "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ==", "integrity": "sha512-GxlsW354Vi6QqbUgdPyQVcQjI7cZBdGV5vOYVYuCVDTylx2wl3WHR2HlhcxxHTrMigbelpXsdcZso+66uxPfow==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tsconfig/node10": { "node_modules/@tsconfig/node10": {
@@ -3157,9 +3335,9 @@
} }
}, },
"node_modules/@types/mssql": { "node_modules/@types/mssql": {
"version": "9.1.7", "version": "9.1.8",
"resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-9.1.7.tgz", "resolved": "https://registry.npmjs.org/@types/mssql/-/mssql-9.1.8.tgz",
"integrity": "sha512-eIOEe78nuSW5KctDHImDhLZ9a+jV/z/Xs5RBhcG/jrk+YWqhdNmzBmHVWV7aWQ5fW+jbIGtX6Ph+bbVqfhzafg==", "integrity": "sha512-mt9h5jWj+DYE5jxnKaWSV/GqDf9FV52XYVk6T3XZF69noEe+JJV6MKirii48l81+cjmAkSq+qeKX+k61fHkYrQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3169,16 +3347,18 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.3.0", "version": "24.7.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.1.tgz",
"integrity": "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~7.10.0" "undici-types": "~7.14.0"
} }
}, },
"node_modules/@types/nodemailer": { "node_modules/@types/nodemailer": {
"version": "7.0.1", "version": "7.0.2",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.2.tgz",
"integrity": "sha512-UfHAghPmGZVzaL8x9y+mKZMWyHC399+iq0MOmya5tIyenWX3lcdSb60vOmp0DocR6gCDTYTozv/ULQnREyyjkg==", "integrity": "sha512-Zo6uOA9157WRgBk/ZhMpTQ/iCWLMk7OIs/Q9jvHarMvrzUUP/MDdPHL2U1zpf57HrrWGv4nYQn5uIxna0xY3xw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3500,6 +3680,15 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"license": "MIT",
"engines": {
"node": "^4.5.0 || >= 5.9"
}
},
"node_modules/basic-auth": { "node_modules/basic-auth": {
"version": "2.0.1", "version": "2.0.1",
"license": "MIT", "license": "MIT",
@@ -3515,38 +3704,49 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/better-auth": { "node_modules/better-auth": {
"version": "1.3.9", "version": "1.3.27",
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.3.9.tgz", "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.3.27.tgz",
"integrity": "sha512-Ty6BHzuShlqSs7I4RMlBRQ3duOWNB7WWriIu2FJVGjQAOtTVvamzFCR4/j5ROFLoNkpvNTRF7BJozsrMICL1gw==", "integrity": "sha512-SwiGAJ7yU6dBhNg0NdV1h5M8T5sa7/AszZVc4vBfMDrLLmvUfbt9JoJ0uRUJUEdKRAAxTyl9yA+F3+GhtAD80w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@better-auth/utils": "0.2.6", "@better-auth/core": "1.3.27",
"@better-fetch/fetch": "^1.1.18", "@better-auth/utils": "0.3.0",
"@better-fetch/fetch": "1.1.18",
"@noble/ciphers": "^2.0.0", "@noble/ciphers": "^2.0.0",
"@noble/hashes": "^2.0.0", "@noble/hashes": "^2.0.0",
"@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/browser": "^13.1.2",
"@simplewebauthn/server": "^13.1.2", "@simplewebauthn/server": "^13.1.2",
"better-call": "1.0.18", "better-call": "1.0.19",
"defu": "^6.1.4", "defu": "^6.1.4",
"jose": "^6.1.0", "jose": "^6.1.0",
"kysely": "^0.28.5", "kysely": "^0.28.5",
"nanostores": "^0.11.4", "nanostores": "^1.0.1",
"zod": "^4.1.5" "zod": "^4.1.5"
}, },
"peerDependencies": {
"@lynx-js/react": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@lynx-js/react": { "@lynx-js/react": {
"optional": true "optional": true
}, },
"@sveltejs/kit": {
"optional": true
},
"next": {
"optional": true
},
"react": { "react": {
"optional": true "optional": true
}, },
"react-dom": { "react-dom": {
"optional": true "optional": true
},
"solid-js": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
} }
} }
}, },
@@ -3575,10 +3775,11 @@
} }
}, },
"node_modules/better-call": { "node_modules/better-call": {
"version": "1.0.18", "version": "1.0.19",
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.18.tgz", "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.19.tgz",
"integrity": "sha512-Ojyck3P3fs/egBmCW50tvfbCJorNV5KphfPOKrkCxPfOr8Brth1ruDtAJuhHVHEUiWrXv+vpEgWQk7m7FzhbbQ==", "integrity": "sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw==",
"dependencies": { "dependencies": {
"@better-auth/utils": "^0.3.0",
"@better-fetch/fetch": "^1.1.4", "@better-fetch/fetch": "^1.1.4",
"rou3": "^0.5.1", "rou3": "^0.5.1",
"set-cookie-parser": "^2.7.1", "set-cookie-parser": "^2.7.1",
@@ -4950,9 +5151,9 @@
} }
}, },
"node_modules/drizzle-kit": { "node_modules/drizzle-kit": {
"version": "0.31.4", "version": "0.31.5",
"resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.4.tgz", "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.5.tgz",
"integrity": "sha512-tCPWVZWZqWVx2XUsVpJRnH9Mx0ClVOf5YUHerZ5so1OKSlqww4zy1R5ksEdGRcO3tM3zj0PYN6V48TbQCL1RfA==", "integrity": "sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@drizzle-team/brocli": "^0.10.2", "@drizzle-team/brocli": "^0.10.2",
@@ -4965,9 +5166,9 @@
} }
}, },
"node_modules/drizzle-orm": { "node_modules/drizzle-orm": {
"version": "0.44.5", "version": "0.44.6",
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.44.5.tgz", "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.44.6.tgz",
"integrity": "sha512-jBe37K7d8ZSKptdKfakQFdeljtu3P2Cbo7tJoJSVZADzIKOBo9IAJPOmMsH2bZl90bZgh8FQlD8BjxXA/zuBkQ==", "integrity": "sha512-uy6uarrrEOc9K1u5/uhBFJbdF5VJ5xQ/Yzbecw3eAYOunv5FDeYkR2m8iitocdHBOHbvorviKOW5GVw0U1j4LQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peerDependencies": { "peerDependencies": {
"@aws-sdk/client-rds-data": ">=3", "@aws-sdk/client-rds-data": ">=3",
@@ -5178,6 +5379,95 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/engine.io": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io/node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/env-paths": { "node_modules/env-paths": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -5513,15 +5803,6 @@
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
"node_modules/fast-redact": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz",
"integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/fast-safe-stringify": { "node_modules/fast-safe-stringify": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
@@ -7598,17 +7879,16 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/mssql": { "node_modules/mssql": {
"version": "11.0.1", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/mssql/-/mssql-11.0.1.tgz", "resolved": "https://registry.npmjs.org/mssql/-/mssql-12.0.0.tgz",
"integrity": "sha512-KlGNsugoT90enKlR8/G36H0kTxPthDhmtNUCwEHvgRza5Cjpjoj+P2X6eMpFUDN7pFrJZsKadL4x990G8RBE1w==", "integrity": "sha512-FcDQ1Gwe4g3Mhw25R1Onr8N+jmqBTWE/pmtcgxYnAUSIf/vBQMvJfMnyMY8ruOICtBch5+Wgbcfd3REDQSlWpA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tediousjs/connection-string": "^0.5.0", "@tediousjs/connection-string": "^0.6.0",
"commander": "^11.0.0", "commander": "^11.0.0",
"debug": "^4.3.3", "debug": "^4.3.3",
"rfdc": "^1.3.0",
"tarn": "^3.0.2", "tarn": "^3.0.2",
"tedious": "^18.2.1" "tedious": "^19.0.0"
}, },
"bin": { "bin": {
"mssql": "bin/mssql" "mssql": "bin/mssql"
@@ -7625,9 +7905,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/nanostores": { "node_modules/nanostores": {
"version": "0.11.4", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.4.tgz", "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.0.1.tgz",
"integrity": "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==", "integrity": "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -7636,7 +7916,7 @@
], ],
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.0.0 || >=20.0.0" "node": "^20.0.0 || >=22.0.0"
} }
}, },
"node_modules/native-duplexpair": { "node_modules/native-duplexpair": {
@@ -7659,9 +7939,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/nodemailer": { "node_modules/nodemailer": {
"version": "7.0.6", "version": "7.0.9",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.6.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.9.tgz",
"integrity": "sha512-F44uVzgwo49xboqbFgBGkRaiMgtoBrBEWCVincJPK9+S9Adkzt/wXCLKbf7dxucmxfTI5gHGB+bEmdyzN6QKjw==", "integrity": "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ==",
"license": "MIT-0", "license": "MIT-0",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@@ -7704,6 +7984,20 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/npm-check-updates": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.0.0.tgz",
"integrity": "sha512-qcfjZEv6xB+WvW24S8wU1MKISPPiTREraBg62XDo/7zmOLXH3Zj7ti2v/LRfks0qITU8SDZLTWwgIitflvursw==",
"license": "Apache-2.0",
"bin": {
"ncu": "build/cli.js",
"npm-check-updates": "build/cli.js"
},
"engines": {
"node": ">=20.0.0",
"npm": ">=8.12.1"
}
},
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -8235,13 +8529,12 @@
} }
}, },
"node_modules/pino": { "node_modules/pino": {
"version": "9.9.0", "version": "10.0.0",
"resolved": "https://registry.npmjs.org/pino/-/pino-9.9.0.tgz", "resolved": "https://registry.npmjs.org/pino/-/pino-10.0.0.tgz",
"integrity": "sha512-zxsRIQG9HzG+jEljmvmZupOMDUQ0Jpj0yAgE28jQvvrdYTlEaiGwelJpdndMl/MBuRr70heIj83QyqJUWaU8mQ==", "integrity": "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"atomic-sleep": "^1.0.0", "atomic-sleep": "^1.0.0",
"fast-redact": "^3.1.1",
"on-exit-leak-free": "^2.1.0", "on-exit-leak-free": "^2.1.0",
"pino-abstract-transport": "^2.0.0", "pino-abstract-transport": "^2.0.0",
"pino-std-serializers": "^7.0.0", "pino-std-serializers": "^7.0.0",
@@ -8249,6 +8542,7 @@
"quick-format-unescaped": "^4.0.3", "quick-format-unescaped": "^4.0.3",
"real-require": "^0.2.0", "real-require": "^0.2.0",
"safe-stable-stringify": "^2.3.1", "safe-stable-stringify": "^2.3.1",
"slow-redact": "^0.3.0",
"sonic-boom": "^4.0.1", "sonic-boom": "^4.0.1",
"thread-stream": "^3.0.0" "thread-stream": "^3.0.0"
}, },
@@ -8275,9 +8569,9 @@
} }
}, },
"node_modules/pino-pretty": { "node_modules/pino-pretty": {
"version": "13.1.1", "version": "13.1.2",
"resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.1.tgz", "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.2.tgz",
"integrity": "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==", "integrity": "sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"colorette": "^2.0.7", "colorette": "^2.0.7",
@@ -8807,12 +9101,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT"
},
"node_modules/rimraf": { "node_modules/rimraf": {
"version": "2.7.1", "version": "2.7.1",
"dev": true, "dev": true,
@@ -9089,6 +9377,147 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/slow-redact": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/slow-redact/-/slow-redact-0.3.1.tgz",
"integrity": "sha512-NvFvl1GuLZNW4U046Tfi8b26zXo8aBzgCAS2f7yVJR/fArN93mOqSA99cB9uITm92ajSz01bsu1K7SCVVjIMpQ==",
"license": "MIT"
},
"node_modules/socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
"engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/socket.io-adapter": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"license": "MIT",
"dependencies": {
"debug": "~4.3.4",
"ws": "~8.17.1"
}
},
"node_modules/socket.io-adapter/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/sonic-boom": { "node_modules/sonic-boom": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz",
@@ -9372,9 +9801,9 @@
} }
}, },
"node_modules/tedious": { "node_modules/tedious": {
"version": "18.6.1", "version": "19.0.0",
"resolved": "https://registry.npmjs.org/tedious/-/tedious-18.6.1.tgz", "resolved": "https://registry.npmjs.org/tedious/-/tedious-19.0.0.tgz",
"integrity": "sha512-9AvErXXQTd6l7TDd5EmM+nxbOGyhnmdbp/8c3pw+tjaiSXW9usME90ET/CRG1LN1Y9tPMtz/p83z4Q97B4DDpw==", "integrity": "sha512-nmxNBAT72mMVCIYp0Ts0Zzd5+LBQjoXlqigCrIjSo2OERSi04vr3EHq3qJxv/zgrSkg7si03SoIIfekTAadA7w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@azure/core-auth": "^1.7.2", "@azure/core-auth": "^1.7.2",
@@ -9389,7 +9818,7 @@
"sprintf-js": "^1.1.3" "sprintf-js": "^1.1.3"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18.17"
} }
}, },
"node_modules/tedious/node_modules/bl": { "node_modules/tedious/node_modules/bl": {
@@ -9622,9 +10051,9 @@
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/tsx": { "node_modules/tsx": {
"version": "4.20.4", "version": "4.20.6",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.4.tgz", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
"integrity": "sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==", "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -9674,7 +10103,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.9.2", "version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
@@ -9705,7 +10136,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "7.10.0", "version": "7.14.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/universalify": { "node_modules/universalify": {
@@ -9918,6 +10351,27 @@
"version": "1.0.2", "version": "1.0.2",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/wsl-utils": { "node_modules/wsl-utils": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
@@ -10008,9 +10462,9 @@
} }
}, },
"node_modules/zod": { "node_modules/zod": {
"version": "4.1.5", "version": "4.1.12",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.5.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
"integrity": "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==", "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"

View File

@@ -30,7 +30,8 @@
"db:migrate": "npx drizzle-kit push", "db:migrate": "npx drizzle-kit push",
"db:generate": "npx drizzle-kit generate", "db:generate": "npx drizzle-kit generate",
"translateDocs": "cd scripts && node translateScript.js", "translateDocs": "cd scripts && node translateScript.js",
"auth:generate": "npx @better-auth/cli generate --config ./app/src/pkg/auth/auth.ts" "auth:generate": "npx @better-auth/cli generate --config ./app/src/pkg/auth/auth.ts",
"updates": "ncu -g"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -41,42 +42,45 @@
"license": "ISC", "license": "ISC",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@dotenvx/dotenvx": "^1.49.0", "@dotenvx/dotenvx": "^1.51.0",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"axios": "^1.12.2", "axios": "^1.12.2",
"better-auth": "^1.3.9", "better-auth": "^1.3.27",
"cors": "^2.8.5", "cors": "^2.8.5",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0", "date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.31.4", "drizzle-kit": "^0.31.5",
"drizzle-orm": "^0.44.5", "drizzle-orm": "^0.44.6",
"drizzle-zod": "^0.8.3", "drizzle-zod": "^0.8.3",
"express": "^5.1.0", "express": "^5.1.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"morgan": "^1.10.1", "morgan": "^1.10.1",
"mssql": "^11.0.1", "mssql": "^12.0.0",
"nodemailer": "^7.0.6", "nodemailer": "^7.0.9",
"nodemailer-express-handlebars": "^7.0.0", "nodemailer-express-handlebars": "^7.0.0",
"npm-check-updates": "^19.0.0",
"pg": "^8.16.3", "pg": "^8.16.3",
"pino": "^9.9.0", "pino": "^10.0.0",
"pino-pretty": "^13.1.1", "pino-pretty": "^13.1.2",
"postgres": "^3.4.7", "postgres": "^3.4.7",
"zod": "^4.1.5" "socket.io": "^4.8.1",
"zod": "^4.1.12"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.2.6",
"@types/express": "^5.0.3", "@types/express": "^5.0.3",
"@types/morgan": "^1.9.10", "@types/morgan": "^1.9.10",
"@types/mssql": "^9.1.7", "@types/mssql": "^9.1.8",
"@types/node": "^24.3.0", "@types/node": "^24.7.1",
"@types/nodemailer": "^7.0.1", "@types/nodemailer": "^7.0.2",
"@types/nodemailer-express-handlebars": "^4.0.5", "@types/nodemailer-express-handlebars": "^4.0.5",
"concurrently": "^9.2.1", "concurrently": "^9.2.1",
"cz-conventional-changelog": "^3.3.0", "cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0", "standard-version": "^9.5.0",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"tsx": "^4.20.4", "tsx": "^4.20.6",
"typescript": "^5.9.2" "typescript": "^5.9.3"
}, },
"config": { "config": {
"commitizen": { "commitizen": {