Major restructure: Remove Confluence, add V2 data structure, organize for dev/prod

- Import real data from PDF (35 Bambu Lab filaments)
- Remove all Confluence integration and dependencies
- Implement new V2 data structure with proper inventory tracking
- Add backwards compatibility for existing data
- Create enhanced UI components (ColorSwatch, InventoryBadge, MaterialBadge)
- Add advanced filtering with quick filters and multi-criteria search
- Organize codebase for dev/prod environments
- Update Lambda functions to support both V1/V2 formats
- Add inventory summary dashboard
- Clean up project structure and documentation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DaX
2025-06-20 01:12:50 +02:00
parent a2252fa923
commit 18110ab159
40 changed files with 2171 additions and 1094 deletions

View File

@@ -1,4 +1,5 @@
export interface Filament {
id?: string;
brand: string;
tip: string;
finish: string;
@@ -8,4 +9,7 @@ export interface Filament {
otvoreno: string;
kolicina: string;
cena: string;
status?: string;
createdAt?: string;
updatedAt?: string;
}

142
src/types/filament.v2.ts Normal file
View File

@@ -0,0 +1,142 @@
// Version 2 - Improved filament data structure
export type MaterialBase = 'PLA' | 'PETG' | 'ABS' | 'TPU' | 'SILK' | 'CF' | 'WOOD';
export type MaterialModifier = 'Silk' | 'Matte' | 'Glow' | 'Wood' | 'CF';
export type StorageCondition = 'vacuum' | 'sealed' | 'opened' | 'desiccant';
export type Currency = 'RSD' | 'EUR' | 'USD';
export interface Material {
base: MaterialBase;
modifier?: MaterialModifier;
}
export interface Color {
name: string;
hex?: string;
pantone?: string;
}
export interface Weight {
value: number;
unit: 'g' | 'kg';
}
export interface InventoryLocation {
vacuum: number;
opened: number;
printer: number;
}
export interface Inventory {
total: number;
available: number;
inUse: number;
locations: InventoryLocation;
}
export interface Pricing {
purchasePrice?: number;
currency: Currency;
supplier?: string;
purchaseDate?: string;
}
export interface Condition {
isRefill: boolean;
openedDate?: string;
expiryDate?: string;
storageCondition: StorageCondition;
humidity?: number;
}
// Legacy fields for backwards compatibility
export interface LegacyFields {
tip: string;
finish: string;
boja: string;
refill: string;
vakum: string;
otvoreno: string;
kolicina: string;
cena: string;
status?: string;
}
export interface FilamentV2 {
// Identifiers
id: string;
sku?: string;
// Product Info
brand: string;
type: MaterialBase;
material: Material;
color: Color;
// Physical Properties
weight: Weight;
diameter: number;
// Inventory Status
inventory: Inventory;
// Purchase Info
pricing: Pricing;
// Condition
condition: Condition;
// Metadata
tags: string[];
notes?: string;
images?: string[];
// Timestamps
createdAt: string;
updatedAt: string;
lastUsed?: string;
// Backwards compatibility
_legacy?: LegacyFields;
}
// Helper type guards
export const isFilamentV2 = (filament: any): filament is FilamentV2 => {
return filament &&
typeof filament === 'object' &&
'material' in filament &&
'inventory' in filament &&
'condition' in filament;
};
// Utility functions
export const getTotalWeight = (filament: FilamentV2): number => {
const multiplier = filament.weight.unit === 'kg' ? 1000 : 1;
return filament.inventory.total * filament.weight.value * multiplier;
};
export const getAvailableWeight = (filament: FilamentV2): number => {
const multiplier = filament.weight.unit === 'kg' ? 1000 : 1;
return filament.inventory.available * filament.weight.value * multiplier;
};
export const isLowStock = (filament: FilamentV2, threshold = 1): boolean => {
return filament.inventory.available <= threshold && filament.inventory.total > 0;
};
export const needsRefill = (filament: FilamentV2): boolean => {
return filament.inventory.available === 0 && filament.inventory.total > 0;
};
export const isExpired = (filament: FilamentV2): boolean => {
if (!filament.condition.expiryDate) return false;
return new Date(filament.condition.expiryDate) < new Date();
};
export const daysOpen = (filament: FilamentV2): number | null => {
if (!filament.condition.openedDate) return null;
const opened = new Date(filament.condition.openedDate);
const now = new Date();
const diff = now.getTime() - opened.getTime();
return Math.floor(diff / (1000 * 60 * 60 * 24));
};