@wandelbots/wandelbots-js-react-components 2.27.1-pr.feature-add-cycle-timer.368.5bd2083 → 2.27.1-pr.feature-add-cycle-timer.368.7535dcc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wandelbots/wandelbots-js-react-components",
3
- "version": "2.27.1-pr.feature-add-cycle-timer.368.5bd2083",
3
+ "version": "2.27.1-pr.feature-add-cycle-timer.368.7535dcc",
4
4
  "description": "React UI toolkit for building applications on top of the Wandelbots platform",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -6,8 +6,19 @@ import { useTranslation } from "react-i18next"
6
6
  import { externalizeComponent } from "../externalizeComponent"
7
7
 
8
8
  export interface CycleTimerProps {
9
- /** Callback that receives the startNewCycle function for controlling the timer */
10
- onCycleComplete: (startNewCycle: (maxTimeSeconds: number) => void) => void
9
+ /**
10
+ * Callback that receives the timer control functions:
11
+ * - `startNewCycle(maxTimeSeconds, elapsedSeconds?)` - Start a new timer cycle
12
+ * - `pause()` - Pause the countdown while preserving remaining time
13
+ * - `resume()` - Resume countdown from where it was paused
14
+ * - `isPaused()` - Check current pause state
15
+ */
16
+ onCycleComplete: (controls: {
17
+ startNewCycle: (maxTimeSeconds: number, elapsedSeconds?: number) => void
18
+ pause: () => void
19
+ resume: () => void
20
+ isPaused: () => boolean
21
+ }) => void
11
22
  /** Callback fired when a cycle actually completes (reaches zero) */
12
23
  onCycleEnd?: () => void
13
24
  /** Whether the timer should start automatically when maxTime is set */
@@ -28,16 +39,47 @@ export interface CycleTimerProps {
28
39
  * - Shows remaining time prominently in the center (60px font)
29
40
  * - Displays "remaining time" label at top and total time at bottom
30
41
  * - Automatically counts down and triggers callback when reaching zero
42
+ * - Full timer control: start, pause, resume functionality
43
+ * - Support for starting with elapsed time (resume mid-cycle)
31
44
  * - Fully localized with i18next
32
45
  * - Material-UI theming integration
33
46
  * - Small variant with animated progress icon (gauge border only) next to text
34
47
  *
35
- * @param onCycleComplete - Callback that receives the startNewCycle function for controlling the timer
48
+ * @param onCycleComplete - Callback that receives timer control functions
36
49
  * @param onCycleEnd - Optional callback fired when a cycle actually completes (reaches zero)
37
50
  * @param autoStart - Whether to start timer automatically (default: true)
38
51
  * @param variant - Visual variant: "default" (large gauge) or "small" (animated icon with text)
39
52
  * @param compact - For small variant: whether to hide remaining time details
40
53
  * @param className - Additional CSS classes
54
+ *
55
+ * Usage:
56
+ * ```tsx
57
+ * <CycleTimer
58
+ * onCycleComplete={(controls) => {
59
+ * // Start a 5-minute cycle
60
+ * controls.startNewCycle(300)
61
+ *
62
+ * // Or start a 5-minute cycle with 2 minutes already elapsed
63
+ * controls.startNewCycle(300, 120)
64
+ *
65
+ * // Pause the timer
66
+ * controls.pause()
67
+ *
68
+ * // Resume the timer
69
+ * controls.resume()
70
+ *
71
+ * // Check if paused
72
+ * const paused = controls.isPaused()
73
+ * }}
74
+ * onCycleEnd={() => console.log('Cycle completed!')}
75
+ * />
76
+ * ```
77
+ *
78
+ * Control Functions:
79
+ * - `startNewCycle(maxTimeSeconds, elapsedSeconds?)` - Start a new timer cycle
80
+ * - `pause()` - Pause the countdown while preserving remaining time
81
+ * - `resume()` - Resume countdown from where it was paused
82
+ * - `isPaused()` - Check current pause state
41
83
  */
42
84
  export const CycleTimer = externalizeComponent(
43
85
  observer(
@@ -54,29 +96,65 @@ export const CycleTimer = externalizeComponent(
54
96
  const [remainingTime, setRemainingTime] = useState(0)
55
97
  const [maxTime, setMaxTime] = useState(0)
56
98
  const [isRunning, setIsRunning] = useState(false)
99
+ const [isPausedState, setIsPausedState] = useState(false)
57
100
  const intervalRef = useRef<NodeJS.Timeout | null>(null)
58
101
 
59
102
  const startNewCycle = useCallback(
60
- (maxTimeSeconds: number) => {
61
- console.log(`Starting new cycle with ${maxTimeSeconds} seconds`)
103
+ (maxTimeSeconds: number, elapsedSeconds: number = 0) => {
104
+ console.log(
105
+ `Starting new cycle with ${maxTimeSeconds} seconds (${elapsedSeconds} seconds already elapsed)`,
106
+ )
62
107
  setMaxTime(maxTimeSeconds)
63
- setRemainingTime(maxTimeSeconds)
64
- if (autoStart) {
108
+ const remainingSeconds = Math.max(0, maxTimeSeconds - elapsedSeconds)
109
+ setRemainingTime(remainingSeconds)
110
+ setIsPausedState(false)
111
+
112
+ if (remainingSeconds === 0) {
113
+ console.log("Cycle already completed (elapsed time >= max time)")
114
+ setIsRunning(false)
115
+ // Trigger completion callback immediately if time is already up
116
+ if (onCycleEnd) {
117
+ setTimeout(() => onCycleEnd(), 0)
118
+ }
119
+ } else if (autoStart) {
65
120
  console.log("Auto-start enabled, starting timer")
66
121
  setIsRunning(true)
67
122
  } else {
68
123
  console.log("Auto-start disabled, timer set but not started")
69
124
  }
70
125
  },
71
- [autoStart],
126
+ [autoStart, onCycleEnd],
72
127
  )
73
128
 
74
- // Call onCycleComplete immediately to provide the startNewCycle function
129
+ const pause = useCallback(() => {
130
+ console.log("Pausing timer")
131
+ setIsRunning(false)
132
+ setIsPausedState(true)
133
+ }, [])
134
+
135
+ const resume = useCallback(() => {
136
+ if (isPausedState && remainingTime > 0) {
137
+ console.log("Resuming timer")
138
+ setIsRunning(true)
139
+ setIsPausedState(false)
140
+ }
141
+ }, [isPausedState, remainingTime])
142
+
143
+ const isPaused = useCallback(() => {
144
+ return isPausedState
145
+ }, [isPausedState])
146
+
147
+ // Call onCycleComplete immediately to provide the timer control functions
75
148
  useEffect(() => {
76
149
  let isMounted = true
77
150
  const timeoutId = setTimeout(() => {
78
151
  if (isMounted) {
79
- onCycleComplete(startNewCycle)
152
+ onCycleComplete({
153
+ startNewCycle,
154
+ pause,
155
+ resume,
156
+ isPaused,
157
+ })
80
158
  }
81
159
  }, 0)
82
160
 
@@ -84,7 +162,7 @@ export const CycleTimer = externalizeComponent(
84
162
  isMounted = false
85
163
  clearTimeout(timeoutId)
86
164
  }
87
- }, [onCycleComplete, startNewCycle])
165
+ }, [onCycleComplete, startNewCycle, pause, resume, isPaused])
88
166
 
89
167
  useEffect(() => {
90
168
  if (isRunning && remainingTime > 0) {