) => {
const { name, value } = e.target;
diff --git a/database/migrations/013_add_pla_basic_colors.sql b/database/migrations/013_add_pla_basic_colors.sql
index c61e319..6645ed5 100644
--- a/database/migrations/013_add_pla_basic_colors.sql
+++ b/database/migrations/013_add_pla_basic_colors.sql
@@ -32,7 +32,8 @@ INSERT INTO colors (name, hex) VALUES
('Silver', '#A6A9AA'),
('Blue Grey', '#5B6579'),
('Dark Gray', '#555555'),
- ('Black', '#000000')
+ ('Black', '#000000'),
+ ('Latte Brown', '#D3B7A7')
ON CONFLICT (name)
DO UPDATE SET hex = EXCLUDED.hex;
@@ -55,7 +56,7 @@ WHERE c.name IN (
'Mistletoe Green', 'Pink', 'Hot Pink', 'Magenta', 'Red',
'Maroon Red', 'Purple', 'Indigo Purple', 'Turquoise', 'Cyan',
'Cobalt Blue', 'Blue', 'Brown', 'Cocoa Brown', 'Bronze',
- 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black'
+ 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black', 'Latte Brown'
)
AND NOT EXISTS (
SELECT 1 FROM filaments f
@@ -75,7 +76,7 @@ AND boja IN (
'Mistletoe Green', 'Pink', 'Hot Pink', 'Magenta', 'Red',
'Maroon Red', 'Purple', 'Indigo Purple', 'Turquoise', 'Cyan',
'Cobalt Blue', 'Blue', 'Brown', 'Cocoa Brown', 'Bronze',
- 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black'
+ 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black', 'Latte Brown'
);
-- Zero out ALL other filaments (not PLA Basic with these specific colors)
@@ -90,6 +91,6 @@ WHERE NOT (
'Mistletoe Green', 'Pink', 'Hot Pink', 'Magenta', 'Red',
'Maroon Red', 'Purple', 'Indigo Purple', 'Turquoise', 'Cyan',
'Cobalt Blue', 'Blue', 'Brown', 'Cocoa Brown', 'Bronze',
- 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black'
+ 'Gray', 'Silver', 'Blue Grey', 'Dark Gray', 'Black', 'Latte Brown'
)
);
\ No newline at end of file
diff --git a/docs/DATA_STRUCTURE_PROPOSAL.md b/docs/DATA_STRUCTURE_PROPOSAL.md
deleted file mode 100644
index 1256369..0000000
--- a/docs/DATA_STRUCTURE_PROPOSAL.md
+++ /dev/null
@@ -1,255 +0,0 @@
-# Improved Data Structure Proposal
-
-## Current Issues
-1. Mixed languages (English/Serbian)
-2. String fields for numeric/boolean values
-3. Inconsistent status representation
-4. No proper inventory tracking
-5. Missing important metadata
-
-## Proposed Structure
-
-```typescript
-interface Filament {
- // Identifiers
- id: string;
- sku?: string; // For internal tracking
-
- // Product Info
- brand: string;
- type: 'PLA' | 'PETG' | 'ABS' | 'TPU' | 'SILK' | 'CF' | 'WOOD';
- material: {
- base: 'PLA' | 'PETG' | 'ABS' | 'TPU';
- modifier?: 'Silk' | 'Matte' | 'Glow' | 'Wood' | 'CF';
- };
- color: {
- name: string;
- hex?: string; // Color code for UI display
- pantone?: string; // For color matching
- };
-
- // Physical Properties
- weight: {
- value: number; // 1000 for 1kg, 500 for 0.5kg
- unit: 'g' | 'kg';
- };
- diameter: number; // 1.75 or 2.85
-
- // Inventory Status
- inventory: {
- total: number; // Total spools
- available: number; // Available for use
- inUse: number; // Currently being used
- locations: {
- vacuum: number; // In vacuum storage
- opened: number; // Opened but usable
- printer: number; // Loaded in printer
- };
- };
-
- // Purchase Info
- pricing: {
- purchasePrice?: number;
- currency: 'RSD' | 'EUR' | 'USD';
- supplier?: string;
- purchaseDate?: string;
- };
-
- // Condition
- condition: {
- isRefill: boolean;
- openedDate?: string;
- expiryDate?: string;
- storageCondition: 'vacuum' | 'sealed' | 'opened' | 'desiccant';
- humidity?: number; // Last measured
- };
-
- // Metadata
- tags: string[]; // ['premium', 'engineering', 'easy-print']
- notes?: string; // Special handling instructions
- images?: string[]; // S3 URLs for photos
-
- // Timestamps
- createdAt: string;
- updatedAt: string;
- lastUsed?: string;
-}
-```
-
-## Benefits
-
-### 1. **Better Filtering**
-```typescript
-// Find all sealed PLA under 1kg
-filaments.filter(f =>
- f.material.base === 'PLA' &&
- f.weight.value <= 1000 &&
- f.condition.storageCondition === 'vacuum'
-)
-```
-
-### 2. **Inventory Management**
-```typescript
-// Get total available filament weight
-const totalWeight = filaments.reduce((sum, f) =>
- sum + (f.inventory.available * f.weight.value), 0
-);
-
-// Find low stock items
-const lowStock = filaments.filter(f =>
- f.inventory.available <= 1 && f.inventory.total > 0
-);
-```
-
-### 3. **Color Management**
-```typescript
-// Group by color for visualization
-const colorGroups = filaments.reduce((groups, f) => {
- const color = f.color.name;
- groups[color] = groups[color] || [];
- groups[color].push(f);
- return groups;
-}, {});
-```
-
-### 4. **Usage Tracking**
-```typescript
-// Find most used filaments
-const mostUsed = filaments
- .filter(f => f.lastUsed)
- .sort((a, b) => new Date(b.lastUsed) - new Date(a.lastUsed))
- .slice(0, 10);
-```
-
-## Migration Strategy
-
-### Phase 1: Add New Fields (Non-breaking)
-```javascript
-// Update Lambda to handle both old and new structure
-const migrateFilament = (old) => ({
- ...old,
- material: {
- base: old.tip || 'PLA',
- modifier: old.finish !== 'Basic' ? old.finish : undefined
- },
- color: {
- name: old.boja
- },
- weight: {
- value: 1000, // Default 1kg
- unit: 'g'
- },
- inventory: {
- total: parseInt(old.kolicina) || 1,
- available: old.otvoreno ? 0 : 1,
- inUse: 0,
- locations: {
- vacuum: old.vakum ? 1 : 0,
- opened: old.otvoreno ? 1 : 0,
- printer: 0
- }
- },
- condition: {
- isRefill: old.refill === 'Da',
- storageCondition: old.vakum ? 'vacuum' : (old.otvoreno ? 'opened' : 'sealed')
- }
-});
-```
-
-### Phase 2: Update UI Components
-- Create new filter components for material type
-- Add inventory status indicators
-- Color preview badges
-- Storage condition icons
-
-### Phase 3: Enhanced Features
-1. **Barcode/QR Integration**: Generate QR codes for each spool
-2. **Usage History**: Track which prints used which filament
-3. **Alerts**: Low stock, expiry warnings
-4. **Analytics**: Cost per print, filament usage trends
-
-## DynamoDB Optimization
-
-### Current Indexes
-- brand-index
-- tip-index
-- status-index
-
-### Proposed Indexes
-```terraform
-global_secondary_index {
- name = "material-color-index"
- hash_key = "material.base"
- range_key = "color.name"
-}
-
-global_secondary_index {
- name = "inventory-status-index"
- hash_key = "condition.storageCondition"
- range_key = "inventory.available"
-}
-
-global_secondary_index {
- name = "brand-type-index"
- hash_key = "brand"
- range_key = "material.base"
-}
-```
-
-## Example Queries
-
-### Find all available green filaments
-```javascript
-const greenFilaments = await dynamodb.query({
- IndexName: 'material-color-index',
- FilterExpression: 'contains(color.name, :green) AND inventory.available > :zero',
- ExpressionAttributeValues: {
- ':green': 'Green',
- ':zero': 0
- }
-}).promise();
-```
-
-### Get inventory summary
-```javascript
-const summary = await dynamodb.scan({
- TableName: TABLE_NAME,
- ProjectionExpression: 'brand, material.base, inventory'
-}).promise();
-
-const report = summary.Items.reduce((acc, item) => {
- const key = `${item.brand}-${item.material.base}`;
- acc[key] = (acc[key] || 0) + item.inventory.total;
- return acc;
-}, {});
-```
-
-## UI Improvements
-
-### 1. **Visual Inventory Status**
-```tsx
-
- {filament.inventory.locations.vacuum > 0 && (
-
- )}
- {filament.inventory.locations.opened > 0 && (
-
- )}
-
-```
-
-### 2. **Color Swatches**
-```tsx
-
-```
-
-### 3. **Smart Filters**
-- Quick filters: "Ready to use", "Low stock", "Refills only"
-- Material groups: "Standard PLA", "Engineering", "Specialty"
-- Storage status: "Vacuum sealed", "Open spools", "In printer"
-
-Would you like me to implement this improved structure?
\ No newline at end of file
diff --git a/jest.setup.js b/jest.setup.js
index 7823063..95e867d 100644
--- a/jest.setup.js
+++ b/jest.setup.js
@@ -3,4 +3,22 @@ import '@testing-library/jest-dom'
// Add TextEncoder/TextDecoder globals for Node.js environment
const { TextEncoder, TextDecoder } = require('util');
global.TextEncoder = TextEncoder;
-global.TextDecoder = TextDecoder;
\ No newline at end of file
+global.TextDecoder = TextDecoder;
+
+// Mock axios globally
+jest.mock('axios', () => ({
+ create: jest.fn(() => ({
+ get: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ delete: jest.fn(),
+ interceptors: {
+ request: {
+ use: jest.fn()
+ },
+ response: {
+ use: jest.fn()
+ }
+ }
+ }))
+}))
\ No newline at end of file
diff --git a/scripts/add-basic-refills.sql b/scripts/add-basic-refills.sql
deleted file mode 100644
index cc3296d..0000000
--- a/scripts/add-basic-refills.sql
+++ /dev/null
@@ -1,56 +0,0 @@
--- Add 1 refill and 1 spulna for each color as PLA Basic filaments
--- Run this with: psql $DATABASE_URL -f scripts/add-basic-refills.sql
-
--- First show what colors we have
-SELECT name, hex FROM colors ORDER BY name;
-
--- Insert PLA Basic filaments with 1 refill and 1 spulna for each color that doesn't already have one
-INSERT INTO filaments (tip, finish, boja, boja_hex, refill, spulna, kolicina, cena)
-SELECT
- 'PLA' as tip,
- 'Basic' as finish,
- c.name as boja,
- c.hex as boja_hex,
- 1 as refill,
- 1 as spulna,
- 2 as kolicina, -- 1 refill + 1 spulna
- '3999' as cena
-FROM colors c
-WHERE NOT EXISTS (
- SELECT 1 FROM filaments f
- WHERE f.tip = 'PLA'
- AND f.finish = 'Basic'
- AND f.boja = c.name
-)
-ON CONFLICT DO NOTHING;
-
--- Update any existing PLA Basic filaments to have 1 refill and 1 spulna
-UPDATE filaments
-SET refill = 1,
- spulna = 1,
- kolicina = 2 -- Update quantity to reflect 1 refill + 1 spulna
-WHERE tip = 'PLA'
-AND finish = 'Basic'
-AND (refill = 0 OR spulna = 0);
-
--- Show summary
-SELECT
- 'Total PLA Basic filaments with refills and spulna' as description,
- COUNT(*) as count
-FROM filaments
-WHERE tip = 'PLA'
-AND finish = 'Basic'
-AND refill = 1
-AND spulna = 1;
-
--- Show all PLA Basic filaments
-SELECT
- boja as color,
- refill,
- spulna,
- kolicina as quantity,
- cena as price
-FROM filaments
-WHERE tip = 'PLA'
-AND finish = 'Basic'
-ORDER BY boja;
\ No newline at end of file
diff --git a/scripts/run-sale-migration.sh b/scripts/run-sale-migration.sh
deleted file mode 100755
index d1e5bc2..0000000
--- a/scripts/run-sale-migration.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-echo "Running sale fields migration..."
-
-# Get RDS endpoint from AWS
-RDS_ENDPOINT=$(aws rds describe-db-instances --region eu-central-1 --db-instance-identifier filamenteka --query 'DBInstances[0].Endpoint.Address' --output text)
-
-# Get database credentials from Secrets Manager
-DB_CREDS=$(aws secretsmanager get-secret-value --region eu-central-1 --secret-id filamenteka-db-credentials --query 'SecretString' --output text)
-DB_USER=$(echo $DB_CREDS | jq -r '.username')
-DB_PASS=$(echo $DB_CREDS | jq -r '.password')
-DB_NAME=$(echo $DB_CREDS | jq -r '.database')
-
-# Run the migration
-PGPASSWORD="$DB_PASS" psql -h $RDS_ENDPOINT -U $DB_USER -d $DB_NAME -f database/migrations/014_add_sale_fields.sql
-
-echo "Migration completed!"
\ No newline at end of file