Skip to content

Commit a03f794

Browse files
committed
chore: reflect TransitionMode updates in usecases
1 parent 5e4f7e8 commit a03f794

12 files changed

Lines changed: 35 additions & 34 deletions

File tree

usecases/basic/App.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { type FC } from 'react';
22
import { useDispatch } from 'react-redux';
33

4-
import type { TransitionAction } from '~transitions';
4+
import type { StagedAction } from '~transitions';
55

66
import { ActivityFeed } from '~usecases/lib/components/activity/ActivityFeed';
77
import { ProfileCard } from '~usecases/lib/components/profile/ProfileCard';
@@ -143,8 +143,10 @@ export const App: FC = () => {
143143
}
144144
};
145145

146-
/** Route a failed stage action through the correct lifecycle handler */
147-
const retryTransition = (action: TransitionAction) => {
146+
/** Route a failed stage action through the correct lifecycle handler.
147+
* CRUD update payloads are `Partial<T>` — cast to full type since
148+
* failed stage actions always carry the complete entity. */
149+
const retryTransition = (action: StagedAction) => {
148150
if (createEpic.stage.match(action)) return handleCreateEpic(action.payload.item);
149151
if (editEpic.stage.match(action)) return handleEditEpic(action.payload.item as Epic);
150152
if (updateProfile.stage.match(action)) return handleUpdateProfile(action.payload.item);

usecases/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const BannerSvg: FC = () => (
4242
<circle cx="28" cy="20" r="5.5" fill="#ff5f57" />
4343
<circle cx="46" cy="20" r="5.5" fill="#febc2e" />
4444
<circle cx="64" cy="20" r="5.5" fill="#28c840" />
45+
{/* prettier-ignore */}
4546
<g fill="url(#bn-title-grad)">
4647
<text fontFamily="'SFMono-Regular','Consolas','Liberation Mono','Menlo',monospace" fontSize="12.5" xmlSpace="preserve">
4748
<tspan x="85" y="62"> ██████╗ ██████╗ ████████╗██╗███╗ ███╗██╗███████╗████████╗██████╗ ██████╗ ███╗ ██╗</tspan>
@@ -85,6 +86,7 @@ const LifecycleSvg: FC = () => (
8586
</defs>
8687
<rect width="850" height="150" rx="12" fill="#0d1117" />
8788
<rect x="1" y="1" width="848" height="148" rx="11" fill="none" stroke="url(#lc-border-grad)" strokeWidth="1.5" />
89+
{/* prettier-ignore */}
8890
<text fontFamily="'SFMono-Regular','Consolas','Liberation Mono','Menlo',monospace" fontSize="13" xmlSpace="preserve">
8991
<tspan x="30" y="40" fill="#4ade80"> stage</tspan><tspan fill="#484f58"> ───▶ </tspan><tspan fill="#38bdf8">commit</tspan><tspan fill="#484f58"> ✓ stage optimistically, commit on success</tspan>
9092
<tspan x="30" y="65" fill="#484f58"> ├──────▶ </tspan><tspan fill="#c4b5fd">amend</tspan><tspan fill="#484f58"> ↻ update staged transition before committing</tspan>

usecases/lib/components/activity/ActivityFeed.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
22
import { type FC, useRef, useState } from 'react';
33
import { useSelector } from 'react-redux';
44

5-
import type { TransitionAction } from '~transitions';
5+
import type { StagedAction } from '~transitions';
66

77
import { Cross, Spinner } from '~usecases/lib/components/todo/Icons';
88
import { useActivityState } from '~usecases/lib/store/activity/hooks';
@@ -22,7 +22,7 @@ type ActivityItemProps = {
2222
entry: ActivityEntry;
2323
onEdit: (entry: ActivityEntry) => void;
2424
onDismiss: (entry: ActivityEntry) => void;
25-
onRetry: (action: TransitionAction) => void;
25+
onRetry: (action: StagedAction) => void;
2626
};
2727

2828
const ActivityItem: FC<ActivityItemProps> = ({ entry, onEdit, onDismiss, onRetry }) => {
@@ -35,9 +35,9 @@ const ActivityItem: FC<ActivityItemProps> = ({ entry, onEdit, onDismiss, onRetry
3535
if (!message || message === entry.message) return;
3636

3737
if (failedAction) {
38-
const { payload } = failedAction as any;
38+
const { payload } = failedAction as StagedAction<{ item: ActivityEntry }>;
3939
const retry = { ...failedAction, payload: { ...payload, item: { ...payload.item, message } } };
40-
onRetry(retry as TransitionAction);
40+
onRetry(retry);
4141
} else {
4242
onEdit({ ...entry, message, revision: entry.revision + 1 });
4343
}
@@ -99,7 +99,7 @@ type Props = {
9999
onLogActivity: (entry: ActivityEntry) => void;
100100
onEditActivity: (entry: ActivityEntry) => void;
101101
onDismissActivity: (entry: ActivityEntry) => void;
102-
onRetry: (action: TransitionAction) => void;
102+
onRetry: (action: StagedAction) => void;
103103
};
104104

105105
export const ActivityFeed: FC<Props> = ({ onLogActivity, onEditActivity, onDismissActivity, onRetry }) => {

usecases/lib/components/todo/TodoApp.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { FC, PropsWithChildren } from 'react';
22
import { useState } from 'react';
33
import { useSelector } from 'react-redux';
44

5-
import type { TransitionAction } from '~transitions';
5+
import type { StagedAction } from '~transitions';
66

77
import { TodoItem } from '~usecases/lib/components/todo/TodoItem';
88
import { selectOptimisticEpics } from '~usecases/lib/store/epics/selectors';
@@ -13,7 +13,7 @@ type Props = {
1313
onCreateTodo: (todo: Epic) => void;
1414
onEditTodo: (todo: Epic) => void;
1515
onDeleteTodo: (todo: Epic) => void;
16-
onRetry: (action: TransitionAction) => void;
16+
onRetry: (action: StagedAction) => void;
1717
};
1818

1919
export const TodoApp: FC<PropsWithChildren<Props>> = ({ onCreateTodo, onDeleteTodo, onEditTodo, onRetry }) => {

usecases/lib/components/todo/TodoItem.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { clsx } from 'clsx';
22
import { useMemo, useState, type FC } from 'react';
33
import { useSelector } from 'react-redux';
44

5-
import type { TransitionAction } from '~transitions';
5+
import type { StagedAction } from '~transitions';
66

77
import { CheckMark, Cross, Spinner } from '~usecases/lib/components/todo/Icons';
88
import { useEpicState } from '~usecases/lib/store/epics/hooks';
@@ -11,7 +11,7 @@ import type { Epic } from '~usecases/lib/store/types';
1111

1212
type Props = {
1313
todo: Epic;
14-
onRetry: (action: TransitionAction) => void;
14+
onRetry: (action: StagedAction) => void;
1515
onEdit: (todo: Epic) => void;
1616
onDelete: (todo: Epic) => void;
1717
};
@@ -39,9 +39,9 @@ export const TodoItem: FC<Props> = ({ todo, onEdit, onRetry, onDelete }) => {
3939
if (failedAction) {
4040
/** Re-dispatch the failed stage action with the mutation applied.
4141
* The App-level retryTransition routes it through the correct lifecycle. */
42-
const { payload } = failedAction as any;
42+
const { payload } = failedAction as StagedAction<{ item: Epic }>;
4343
const retry = { ...failedAction, payload: { ...payload, item: { ...payload.item, ...mutation } } };
44-
onRetry(retry as TransitionAction);
44+
onRetry(retry);
4545
} else onEdit({ ...todo, revision: todo.revision + 1, ...mutation });
4646
};
4747

usecases/lib/hooks/useAutoRetry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect, useRef } from 'react';
22
import { useSelector } from 'react-redux';
33

4-
import type { TransitionAction } from '~transitions';
4+
import type { StagedAction } from '~transitions';
55

66
import { useMockApi } from '~usecases/lib/components/mocks/MockApiProvider';
77
import { selectAllFailedTransitions } from '~usecases/lib/store/epics/selectors';
@@ -10,7 +10,7 @@ import { selectAllFailedTransitions } from '~usecases/lib/store/epics/selectors'
1010
* `retry` is called with each failed stage action — the App-level
1111
* handler routes it through the correct lifecycle (component async,
1212
* thunk, or saga re-dispatch). */
13-
export const useAutoRetry = (retry: (action: TransitionAction) => void) => {
13+
export const useAutoRetry = (retry: (action: StagedAction) => void) => {
1414
const { online } = useMockApi();
1515
const failedTransitions = useSelector(selectAllFailedTransitions);
1616
const retryRef = useRef(retry);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { createTransitions, crudPrepare } from '~actions';
2-
import { DedupeMode } from '~transitions';
2+
import { TransitionMode } from '~transitions';
33
import type { ActivityEntry } from '~usecases/lib/store/types';
44

55
const crud = crudPrepare<ActivityEntry>('id');
66

77
export const logActivity = createTransitions('activity::add')(crud.create);
88
export const editActivity = createTransitions('activity::edit')(crud.update);
9-
export const dismissActivity = createTransitions('activity::dismiss', DedupeMode.TRAILING)(crud.remove);
9+
export const dismissActivity = createTransitions('activity::dismiss', TransitionMode.REVERTIBLE)(crud.remove);

usecases/lib/store/epics/actions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { createAction } from '@reduxjs/toolkit';
22
import { createTransitions, crudPrepare } from '~actions';
3-
import { DedupeMode } from '~transitions';
3+
import { TransitionMode } from '~transitions';
44
import type { Epic } from '~usecases/lib/store/types';
55

66
const crud = crudPrepare<Epic>('id');
77

88
export const createEpic = createTransitions('epics::add')(crud.create);
99
export const editEpic = createTransitions('epics::edit')(crud.update);
10-
export const deleteEpic = createTransitions('epics::delete', DedupeMode.TRAILING)(crud.remove);
10+
export const deleteEpic = createTransitions('epics::delete', TransitionMode.REVERTIBLE)(crud.remove);
1111

1212
export type OptimisticActions =
1313
| ReturnType<typeof createEpic.stage>

usecases/lib/store/epics/selectors.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createSelector } from '@reduxjs/toolkit';
22
import {
3+
selectAllFailedTransitions as selectAllFailed,
34
selectFailedTransition,
4-
selectFailedTransitions,
55
selectIsConflicting,
66
selectIsFailed,
77
selectIsOptimistic,
@@ -46,10 +46,5 @@ export const selectAllFailedTransitions = createSelector(
4646
(state: State) => state.profile,
4747
(state: State) => state.projects,
4848
(state: State) => state.activity,
49-
(epics, profile, projects, activity) => [
50-
...selectFailedTransitions(epics),
51-
...selectFailedTransitions(profile),
52-
...selectFailedTransitions(projects),
53-
...selectFailedTransitions(activity),
54-
],
49+
(epics, profile, projects, activity) => selectAllFailed(epics, profile, projects, activity),
5550
);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { createTransitions, crudPrepare } from '~actions';
2-
import { DedupeMode } from '~transitions';
2+
import { TransitionMode } from '~transitions';
33
import type { ProjectTodo } from '~usecases/lib/store/types';
44

55
const crud = crudPrepare<ProjectTodo>()(['projectId', 'id']);
66

77
export const createProjectTodo = createTransitions('projects::add')(crud.create);
88
export const editProjectTodo = createTransitions('projects::edit')(crud.update);
9-
export const deleteProjectTodo = createTransitions('projects::delete', DedupeMode.TRAILING)(crud.remove);
9+
export const deleteProjectTodo = createTransitions('projects::delete', TransitionMode.REVERTIBLE)(crud.remove);

0 commit comments

Comments
 (0)