grabbit 46d8af6084 🎉 Epic 2 Milestone: Successfully completed the final story of Epic 2: Commercialization & Core User Experience with full-stack date filtering functionality.
📋 What Was Accomplished

  Backend Changes:
  -  Enhanced API Endpoint: Updated GET /api/v1/events to accept optional date query parameter
  -  Input Validation: Added YYYY-MM-DD format validation to PaginationQueryDto
  -  Database Filtering: Implemented timezone-aware date filtering in EventsService
  -  Controller Integration: Updated EventsController to pass date parameter to service

  Frontend Changes:
  -  Date Picker Component: Created reusable DatePicker component following project design system
  -  Gallery UI Enhancement: Integrated date picker into gallery page with clear labeling
  -  State Management: Implemented reactive date state with automatic re-fetching
  -  Clear Filter Functionality: Added "Clear Filter" button for easy reset
  -  Enhanced UX: Improved empty states for filtered vs unfiltered views

  🔍 Technical Implementation

  API Design:
  GET /api/v1/events?date=2025-08-02&limit=20&cursor=xxx

  Key Files Modified:
  - meteor-web-backend/src/events/dto/pagination-query.dto.ts
  - meteor-web-backend/src/events/events.service.ts
  - meteor-web-backend/src/events/events.controller.ts
  - meteor-frontend/src/components/ui/date-picker.tsx (new)
  - meteor-frontend/src/app/gallery/page.tsx
  - meteor-frontend/src/hooks/use-events.ts
  - meteor-frontend/src/services/events.ts

   All Acceptance Criteria Met

  1.  Backend API Enhancement: Accepts optional date parameter
  2.  Date Filtering Logic: Returns events for specific calendar date
  3.  Date Picker UI: Clean, accessible interface component
  4.  Automatic Re-fetching: Immediate data updates on date selection
  5.  Filtered Display: Correctly shows only events for selected date
  6.  Clear Filter: One-click reset to view all events

  🧪 Quality Assurance

  -  Backend Build: Successful compilation with no errors
  -  Frontend Build: Successful Next.js build with no warnings
  -  Linting: All ESLint checks pass
  -  Functionality: Feature working as specified

  🎉 Epic 2 Complete!

  With Story 2.9 completion, Epic 2: Commercialization & Core User Experience is now DONE!

  Epic 2 Achievements:
  - 🔐 Full-stack device status monitoring
  - 💳 Robust payment and subscription system
  - 🛡️ Subscription-based access control
  - 📊 Enhanced data browsing with detail pages
  - 📅 Date-based event filtering
2025-08-03 10:30:29 +08:00

68 lines
2.3 KiB
JavaScript

const { Client } = require('pg');
require('dotenv').config();
async function seedInventoryDevices() {
console.log('=== Seeding Inventory Devices ===');
const client = new Client({
connectionString: process.env.DATABASE_URL,
ssl: false,
});
try {
await client.connect();
// Sample inventory devices for testing
const deviceData = [
{ hardwareId: 'EDGE_DEVICE_001', deviceModel: 'EdgeBox Pro v1.0' },
{ hardwareId: 'EDGE_DEVICE_002', deviceModel: 'EdgeBox Pro v1.0' },
{ hardwareId: 'EDGE_DEVICE_003', deviceModel: 'EdgeBox Pro v1.1' },
{ hardwareId: 'SENSOR_NODE_001', deviceModel: 'SensorNode Lite v2.0' },
{ hardwareId: 'SENSOR_NODE_002', deviceModel: 'SensorNode Lite v2.0' },
{ hardwareId: 'GATEWAY_HUB_001', deviceModel: 'GatewayHub Enterprise v1.0' },
];
console.log('📦 Inserting sample inventory devices...');
for (const device of deviceData) {
// Check if device already exists
const existsResult = await client.query(
'SELECT id FROM inventory_devices WHERE hardware_id = $1',
[device.hardwareId]
);
if (existsResult.rows.length === 0) {
await client.query(
`INSERT INTO inventory_devices (hardware_id, device_model, is_claimed)
VALUES ($1, $2, false)`,
[device.hardwareId, device.deviceModel]
);
console.log(` ✅ Added: ${device.hardwareId} (${device.deviceModel})`);
} else {
console.log(` ⏭️ Skipped: ${device.hardwareId} (already exists)`);
}
}
// Show current inventory status
const inventoryResult = await client.query(`
SELECT hardware_id, device_model, is_claimed, created_at
FROM inventory_devices
ORDER BY created_at DESC
`);
console.log('\n📋 Current Inventory Status:');
inventoryResult.rows.forEach(row => {
const status = row.is_claimed ? '🔴 CLAIMED' : '🟢 AVAILABLE';
console.log(` ${status} ${row.hardware_id} - ${row.device_model || 'No model'}`);
});
console.log(`\n✅ Seeding completed! ${deviceData.length} devices processed.`);
} catch (error) {
console.error('❌ Error seeding inventory devices:', error.message);
} finally {
await client.end();
}
}
seedInventoryDevices();