From 98d6265ae10e90855ca9b6d16f446ca1270995f5 Mon Sep 17 00:00:00 2001 From: GotthardG <51994228+GotthardG@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:43:26 +0100 Subject: [PATCH] now associating a dewar to a slot --- backend/app/models.py | 18 ++++++----- backend/app/routers/logistics.py | 20 ++++++++++++- logistics/src/components/CountdownTimer.tsx | 33 +++++++++++++++++++++ logistics/src/components/Slots.tsx | 8 ++++- 4 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 logistics/src/components/CountdownTimer.tsx diff --git a/backend/app/models.py b/backend/app/models.py index 914ac49..21ca17e 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -79,7 +79,6 @@ class Dewar(Base): contact_person_id = Column(Integer, ForeignKey("contact_persons.id")) shipment = relationship("Shipment", back_populates="dewars") - events = relationship("LogisticsEvent", back_populates="dewar") return_address = relationship("Address") contact_person = relationship("ContactPerson") pucks = relationship("Puck", back_populates="dewar") @@ -87,6 +86,7 @@ class Dewar(Base): dewar_type = relationship("DewarType") dewar_serial_number = relationship("DewarSerialNumber") slot = relationship("Slot", back_populates="dewar") + events = relationship("LogisticsEvent", back_populates="dewar") @property def number_of_pucks(self) -> int: @@ -147,6 +147,7 @@ class Slot(Base): time_until_refill = Column(Integer) # store as total seconds dewar_unique_id = Column(String, ForeignKey('dewars.unique_id'), nullable=True) # Added field dewar = relationship("Dewar", back_populates="slot") + events = relationship("LogisticsEvent", back_populates="slot") @property @@ -155,13 +156,14 @@ class Slot(Base): return self.last_refill + self.time_until_refill - datetime.utcnow() return None - class LogisticsEvent(Base): - __tablename__ = 'logistics_events' - id = Column(Integer, primary_key=True, index=True, autoincrement=True) - dewar_id = Column(Integer, ForeignKey('dewars.id'), nullable=False) - event_type = Column(String, nullable=False) - timestamp = Column(DateTime, default=datetime.utcnow) + __tablename__ = "logistics_events" + id = Column(Integer, primary_key=True, index=True) + dewar_id = Column(Integer, ForeignKey('dewars.id')) # corrected table name + slot_id = Column(Integer, ForeignKey('slots.id')) # corrected table name + event_type = Column(String, index=True) + timestamp = Column(DateTime, default=datetime.utcnow) + action_details = Column(String) dewar = relationship("Dewar", back_populates="events") - slot_id = Column(String, ForeignKey('slots.id'), nullable=True) \ No newline at end of file + slot = relationship("Slot", back_populates="events") \ No newline at end of file diff --git a/backend/app/routers/logistics.py b/backend/app/routers/logistics.py index 1b7077a..f9705b9 100644 --- a/backend/app/routers/logistics.py +++ b/backend/app/routers/logistics.py @@ -87,4 +87,22 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get def log_event(db: Session, dewar_id: int, slot_id: int, event_type: str): new_event = LogisticsEventModel(dewar_id=dewar_id, slot_id=slot_id, event_type=event_type) db.add(new_event) - db.commit() \ No newline at end of file + db.commit() + + +@router.post("/dewar/refill", response_model=dict) +async def refill_dewar(qr_code: str, db: Session = Depends(get_db)): + dewar = db.query(DewarModel).filter(DewarModel.unique_id == qr_code).first() + if not dewar: + raise HTTPException(status_code=404, detail="Dewar not found") + + # Process refill + dewar.last_refill = datetime.now() + new_event = LogisticsEventModel( + dewar_id=dewar.id, slot_id=None, # No specific slot, as it's a refill event + event_type="refill", + action_details=f"{dewar.unique_id} refilled" + ) + db.add(new_event) + db.commit() + return {"message": "Dewar refilled successfully"} \ No newline at end of file diff --git a/logistics/src/components/CountdownTimer.tsx b/logistics/src/components/CountdownTimer.tsx new file mode 100644 index 0000000..a70b932 --- /dev/null +++ b/logistics/src/components/CountdownTimer.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useState } from 'react'; +import { Typography } from '@mui/material'; + +interface CountdownTimerProps { + totalSeconds: number; +} + +const CountdownTimer: React.FC = ({ totalSeconds }) => { + const [timeLeft, setTimeLeft] = useState(totalSeconds); + + useEffect(() => { + const timerId = setInterval(() => { + setTimeLeft(prev => Math.max(prev - 1, 0)); + }, 1000); + + return () => clearInterval(timerId); + }, []); + + const formatTime = (seconds: number) => { + const hrs = Math.floor(seconds / 3600); + const min = Math.floor((seconds % 3600) / 60); + const sec = seconds % 60; + return `${hrs}h ${min}m ${sec}s`; + }; + + return ( + {/* Warn with red color if less than 5 minutes */} + {`Time until refill: ${formatTime(timeLeft)}`} + + ); +}; + +export default CountdownTimer; \ No newline at end of file diff --git a/logistics/src/components/Slots.tsx b/logistics/src/components/Slots.tsx index f702403..e6afec5 100644 --- a/logistics/src/components/Slots.tsx +++ b/logistics/src/components/Slots.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Box, Typography } from '@mui/material'; import styled from 'styled-components'; import LocalGasStationIcon from '@mui/icons-material/LocalGasStation'; // Icon for refilling indicator. +import CountdownTimer from './CountdownTimer'; // Import the CountdownTimer component export interface SlotData { id: string; @@ -12,6 +13,7 @@ export interface SlotData { dewar_unique_id?: string; // Optional additional information. dewar_name?: string; // Optional dewar information. needs_refill?: boolean; // Indicator for refill requirement. + time_until_refill?: number; // Time until refill in seconds, optional field } interface SlotProps { @@ -24,7 +26,7 @@ const StyledSlot = styled(Box)<{ isSelected: boolean; isOccupied: boolean }>` padding: 16px; margin: 8px; width: 150px; // Increase the width to accommodate more info. - height: 150px; // Increase the height to accommodate more info. + height: 200px; // Increase the height to accommodate more info. background-color: ${({ isSelected, isOccupied }) => isSelected ? '#3f51b5' : isOccupied ? '#f44336' : '#4caf50'}; color: white; @@ -57,6 +59,10 @@ const Slot: React.FC = ({ data, isSelected, onSelect }) => { {`ID: ${data.dewar_unique_id}`} )} {data.needs_refill && } + {/* Display countdown timer only for slots that have an associated dewar */} + {data.dewar_unique_id && data.time_until_refill !== undefined && ( + + )} ); };