From 5cc27f852b02446659e0ab85305916c9f5e5a5f0 Mon Sep 17 00:00:00 2001
From: Ariel Costas Guerrero <ariel@costas.dev>
Date: Wed, 6 Aug 2025 00:12:19 +0200
Subject: feat: Implement pull-to-refresh functionality across various
 components

- Added `PullToRefresh` component to enable pull-to-refresh behavior in `StopList` and `Estimates` pages.
- Integrated `usePullToRefresh` hook to manage pull-to-refresh state and actions.
- Created `UpdateNotification` component to inform users of available updates from the service worker.
- Enhanced service worker management with `ServiceWorkerManager` class for better update handling and caching strategies.
- Updated CSS styles for new components and improved layout for better user experience.
- Refactored API caching logic in service worker to handle multiple endpoints and dynamic cache expiration.
- Added auto-refresh functionality for estimates data to keep information up-to-date.
---
 src/frontend/app/components/PullToRefresh.tsx | 53 +++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 src/frontend/app/components/PullToRefresh.tsx

(limited to 'src/frontend/app/components/PullToRefresh.tsx')

diff --git a/src/frontend/app/components/PullToRefresh.tsx b/src/frontend/app/components/PullToRefresh.tsx
new file mode 100644
index 0000000..47a6f03
--- /dev/null
+++ b/src/frontend/app/components/PullToRefresh.tsx
@@ -0,0 +1,53 @@
+import { type ReactNode } from "react";
+import { RotateCcw } from "lucide-react";
+import "./PullToRefresh.css";
+
+interface PullToRefreshIndicatorProps {
+  pullDistance: number;
+  isRefreshing: boolean;
+  canRefresh: boolean;
+  children: ReactNode;
+}
+
+export function PullToRefreshIndicator({
+  pullDistance,
+  isRefreshing,
+  canRefresh,
+  children,
+}: PullToRefreshIndicatorProps) {
+  const opacity = Math.min(pullDistance / 60, 1);
+  const rotation = isRefreshing ? 360 : pullDistance * 4;
+  const scale = Math.min(0.5 + (pullDistance / 120), 1);
+
+  return (
+    <div className="pull-to-refresh-container">
+      <div 
+        className="pull-to-refresh-indicator"
+        style={{
+          transform: `translateY(${Math.min(pullDistance, 80)}px)`,
+          opacity: opacity,
+        }}
+      >
+        <div 
+          className={`pull-to-refresh-icon ${isRefreshing ? 'spinning' : ''} ${canRefresh ? 'ready' : ''}`}
+          style={{
+            transform: `rotate(${rotation}deg) scale(${scale})`,
+          }}
+        >
+          <RotateCcw size={24} />
+        </div>
+        <div className="pull-to-refresh-text">
+          {isRefreshing ? "Actualizando..." : canRefresh ? "Suelta para actualizar" : "Arrastra para actualizar"}
+        </div>
+      </div>
+      <div 
+        className="pull-to-refresh-content"
+        style={{
+          transform: `translateY(${Math.min(pullDistance * 0.5, 40)}px)`,
+        }}
+      >
+        {children}
+      </div>
+    </div>
+  );
+}
-- 
cgit v1.3

