mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 20:52:09 +01:00
Security Enhancements: - Implemented proper rate limiting with automatic cleanup for /register and /forgot-password endpoints - Added memory usage protection with MAX_ENTRIES limit (10000) - Fixed rate limiter memory leaks by adding cleanup intervals - Improved IP extraction with x-real-ip and x-client-ip header support Code Quality Improvements: - Refactored ProcessingStatusManager from individual functions to class-based architecture - Maintained backward compatibility with singleton instance pattern - Fixed TypeScript strict mode violations across the codebase - Resolved all build errors and type mismatches UI Component Fixes: - Removed unused chart components (Charts.tsx, DonutChart.tsx) - Fixed calendar component type issues by removing unused custom implementations - Resolved theme provider type imports - Fixed confetti component default options handling - Corrected pointer component coordinate type definitions Type System Improvements: - Extended NextAuth types to support dual auth systems (regular and platform users) - Fixed nullable type handling throughout the codebase - Resolved Prisma JSON field type compatibility issues - Corrected SessionMessage and ImportRecord interface definitions - Fixed ES2015 iteration compatibility issues Database & Performance: - Updated database pool configuration for Prisma adapter compatibility - Fixed pagination response structure in user management endpoints - Improved error handling with proper error class usage Testing & Build: - All TypeScript compilation errors resolved - ESLint warnings remain but no errors - Build completes successfully with proper static generation
151 lines
3.3 KiB
TypeScript
151 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import type {
|
|
GlobalOptions as ConfettiGlobalOptions,
|
|
CreateTypes as ConfettiInstance,
|
|
Options as ConfettiOptions,
|
|
} from "canvas-confetti";
|
|
import confetti from "canvas-confetti";
|
|
import type React from "react";
|
|
import type { ReactNode } from "react";
|
|
import {
|
|
createContext,
|
|
forwardRef,
|
|
useCallback,
|
|
useEffect,
|
|
useImperativeHandle,
|
|
useMemo,
|
|
useRef,
|
|
} from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
type Api = {
|
|
fire: (options?: ConfettiOptions) => void;
|
|
};
|
|
|
|
type Props = React.ComponentPropsWithRef<"canvas"> & {
|
|
options?: ConfettiOptions;
|
|
globalOptions?: ConfettiGlobalOptions;
|
|
manualstart?: boolean;
|
|
children?: ReactNode;
|
|
};
|
|
|
|
export type ConfettiRef = Api | null;
|
|
|
|
const ConfettiContext = createContext<Api>({} as Api);
|
|
|
|
// Define component first
|
|
const ConfettiComponent = forwardRef<ConfettiRef, Props>((props, ref) => {
|
|
const {
|
|
options,
|
|
globalOptions = { resize: true, useWorker: true },
|
|
manualstart = false,
|
|
children,
|
|
...rest
|
|
} = props;
|
|
const instanceRef = useRef<ConfettiInstance | null>(null);
|
|
|
|
const canvasRef = useCallback(
|
|
(node: HTMLCanvasElement) => {
|
|
if (node !== null) {
|
|
if (instanceRef.current) return;
|
|
instanceRef.current = confetti.create(node, {
|
|
...globalOptions,
|
|
resize: true,
|
|
});
|
|
} else {
|
|
if (instanceRef.current) {
|
|
instanceRef.current.reset();
|
|
instanceRef.current = null;
|
|
}
|
|
}
|
|
},
|
|
[globalOptions]
|
|
);
|
|
|
|
const fire = useCallback(
|
|
async (opts = {}) => {
|
|
try {
|
|
await instanceRef.current?.({ ...options, ...opts });
|
|
} catch (error) {
|
|
console.error("Confetti error:", error);
|
|
}
|
|
},
|
|
[options]
|
|
);
|
|
|
|
const api = useMemo(
|
|
() => ({
|
|
fire,
|
|
}),
|
|
[fire]
|
|
);
|
|
|
|
useImperativeHandle(ref, () => api, [api]);
|
|
|
|
useEffect(() => {
|
|
if (!manualstart) {
|
|
(async () => {
|
|
try {
|
|
await fire();
|
|
} catch (error) {
|
|
console.error("Confetti effect error:", error);
|
|
}
|
|
})();
|
|
}
|
|
}, [manualstart, fire]);
|
|
|
|
return (
|
|
<ConfettiContext.Provider value={api}>
|
|
<canvas ref={canvasRef} {...rest} />
|
|
{children}
|
|
</ConfettiContext.Provider>
|
|
);
|
|
});
|
|
|
|
// Set display name immediately
|
|
ConfettiComponent.displayName = "Confetti";
|
|
|
|
// Export as Confetti
|
|
export const Confetti = ConfettiComponent;
|
|
|
|
interface ConfettiButtonProps extends React.ComponentProps<typeof Button> {
|
|
options?: ConfettiOptions &
|
|
ConfettiGlobalOptions & { canvas?: HTMLCanvasElement };
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
const ConfettiButtonComponent = ({
|
|
options,
|
|
children,
|
|
...props
|
|
}: ConfettiButtonProps) => {
|
|
const handleClick = async (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
try {
|
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
const x = rect.left + rect.width / 2;
|
|
const y = rect.top + rect.height / 2;
|
|
await confetti({
|
|
...options,
|
|
origin: {
|
|
x: x / window.innerWidth,
|
|
y: y / window.innerHeight,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error("Confetti button error:", error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Button onClick={handleClick} {...props}>
|
|
{children}
|
|
</Button>
|
|
);
|
|
};
|
|
|
|
ConfettiButtonComponent.displayName = "ConfettiButton";
|
|
|
|
export const ConfettiButton = ConfettiButtonComponent;
|