diff --git a/client/index.html b/client/index.html
index e4b78ea..9603ad9 100644
--- a/client/index.html
+++ b/client/index.html
@@ -4,7 +4,7 @@
-
Vite + React + TS
+ Task Receipts
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 1a63a45..c341bac 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -89,6 +89,7 @@ export function App() {
onTaskSelect={setSelectedTask}
onStepSelect={setSelectedStep}
onBack={handleBack}
+ onPrintTask={handlePrintTask}
onPrintStep={handlePrintStep}
onAddNote={handleAddNote}
/>
diff --git a/client/src/layouts/DesktopLayout.tsx b/client/src/layouts/DesktopLayout.tsx
index 7c45da0..4556f3a 100644
--- a/client/src/layouts/DesktopLayout.tsx
+++ b/client/src/layouts/DesktopLayout.tsx
@@ -125,7 +125,7 @@ export function DesktopLayout({
}}
>
onStepSelect(step)} sx={{ flex: 1 }}>
- {step.name}
+ {step.order}: {step.name}
{onPrintStep && selectedUser && (
);
-}
\ No newline at end of file
+}
diff --git a/client/src/layouts/MobileLayout.tsx b/client/src/layouts/MobileLayout.tsx
index 360c814..c540481 100644
--- a/client/src/layouts/MobileLayout.tsx
+++ b/client/src/layouts/MobileLayout.tsx
@@ -3,6 +3,7 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import PrintIcon from '@mui/icons-material/Print';
import type { GroupWithTasks, TaskWithSteps, StepWithNotes } from '../types';
import { CreateButtons } from '../components/CreateButtons';
+import { useUserSelection } from '../hooks/useUserSelection';
function isGroupView(selectedGroup?: GroupWithTasks) {
return !selectedGroup;
@@ -16,6 +17,10 @@ function isStepView(selectedTask?: TaskWithSteps, selectedStep?: StepWithNotes)
return selectedTask && !selectedStep;
}
+function isGroupWithTasks(group: any): group is GroupWithTasks {
+ return group && typeof group.id === 'string' && Array.isArray(group.tasks);
+}
+
export function MobileLayout({
groups = [],
selectedGroup,
@@ -25,6 +30,7 @@ export function MobileLayout({
onTaskSelect,
onStepSelect,
onBack,
+ onPrintTask,
onPrintStep,
onAddNote
}: {
@@ -36,9 +42,11 @@ export function MobileLayout({
onTaskSelect: (task: TaskWithSteps | undefined) => void;
onStepSelect: (step: StepWithNotes | undefined) => void;
onBack: () => void;
+ onPrintTask?: (taskId: string, userId: string) => void;
onPrintStep?: (stepId: string, userId: string) => void;
onAddNote?: (content: string) => void;
}) {
+ const { selectedUser } = useUserSelection();
const groupList: GroupWithTasks[] = groups;
const taskList: TaskWithSteps[] = (selectedGroup?.tasks as TaskWithSteps[]) ?? [];
const stepList: StepWithNotes[] = (selectedTask?.steps as StepWithNotes[]) ?? [];
@@ -61,6 +69,14 @@ export function MobileLayout({
{selectedTask.name}
+ {onPrintTask && selectedUser && (
+ onPrintTask(String(selectedTask.id), String(selectedUser.id))}
+ sx={{ ml: 'auto' }}
+ >
+
+
+ )}
)}
@@ -70,9 +86,9 @@ export function MobileLayout({
{selectedStep.name}
- {onPrintStep && (
+ {onPrintStep && selectedUser && (
onPrintStep(String(selectedStep.id), '1')} // TODO: Get real user ID
+ onClick={() => onPrintStep(String(selectedStep.id), String(selectedUser.id))}
sx={{ ml: 'auto' }}
>
@@ -97,7 +113,7 @@ export function MobileLayout({
sx={{
p: 2,
cursor: 'pointer',
- bgcolor: selectedGroup?.id === group.id ? 'action.selected' : 'transparent',
+ // no bg color
'&:hover': { bgcolor: 'action.hover' },
}}
onClick={() => onGroupSelect(group)}
@@ -108,7 +124,7 @@ export function MobileLayout({
>
)}
- {isTaskView(selectedGroup, selectedTask) && (
+ {isTaskView(selectedGroup, selectedTask) && isGroupWithTasks(selectedGroup) && (
<>
Tasks
@@ -121,11 +137,27 @@ export function MobileLayout({
sx={{
p: 2,
cursor: 'pointer',
- bgcolor: selectedTask?.id === task.id ? 'action.selected' : 'transparent',
+ // no bg color
+ '&:hover': { bgcolor: 'action.hover' },
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
}}
- onClick={() => onTaskSelect(task)}
>
- {task.name}
+ onTaskSelect(task)} sx={{ flex: 1 }}>
+ {task.name}
+
+ {onPrintTask && selectedUser && (
+ {
+ e.stopPropagation();
+ onPrintTask(String(task.id), String(selectedUser.id));
+ }}
+ >
+
+
+ )}
))}
@@ -146,10 +178,25 @@ export function MobileLayout({
p: 2,
cursor: 'pointer',
bgcolor: selectedStep?.id === step.id ? 'action.selected' : 'transparent',
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
}}
- onClick={() => onStepSelect(step)}
>
- {step.name}
+ onStepSelect(step)} sx={{ flex: 1 }}>
+ {step.order}: {step.name}
+
+ {onPrintStep && selectedUser && (
+ {
+ e.stopPropagation();
+ onPrintStep(String(step.id), String(selectedUser.id));
+ }}
+ >
+
+
+ )}
))}
@@ -191,4 +238,4 @@ export function MobileLayout({
);
-}
\ No newline at end of file
+}
diff --git a/server/src/printer/format-utils.ts b/server/src/printer/format-utils.ts
index c57c590..28f9f6f 100644
--- a/server/src/printer/format-utils.ts
+++ b/server/src/printer/format-utils.ts
@@ -24,10 +24,11 @@ export const formatUtils = {
* @param startIndex Starting index for numbering (0 for no numbers)
* @returns Array of formatted lines
*/
- formatList(items: string[], startIndex: number = 0): string[] {
+ formatList(items: string[], startIndex: number = 0, prefix: string = ''): string[] {
return items.map((item, index) => {
const num = startIndex > 0 ? `${index + startIndex}: ` : '';
- return this.formatCheckbox(`${num}${item}`);
+ const body = this.formatCheckbox(`${num}${item}`);
+ return `${prefix}${body}`;
});
},
diff --git a/server/src/printer/test-printer.ts b/server/src/printer/test-printer.ts
index 118b358..7786f51 100644
--- a/server/src/printer/test-printer.ts
+++ b/server/src/printer/test-printer.ts
@@ -37,15 +37,10 @@ export class TestPrinter implements Printer {
const content = [
...formatUtils.formatSection(`Task: ${task.name}`, ''),
- ...taskSteps.map((step, index) =>
- formatUtils.formatSection(
- formatUtils.formatStepHeader(step.name, index + 1, task.name, true),
- step.instructions,
- '-',
- true,
- )
- ).flat(),
- ].join('\n');
+ ...formatUtils.formatList(taskSteps.map((step, index) =>
+ formatUtils.formatStepHeader(step.name, index + 1, task.name, true)
+ ), 0, '- '),
+ ].join('\n') + '\n';
await fs.writeFile(filename, content);
logger.info(`Printed task ${task.id} to ${filename}`);
@@ -69,7 +64,7 @@ export class TestPrinter implements Printer {
const content = formatUtils.formatSection(
formatUtils.formatStepHeader(step.name, stepNumber, task?.name),
step.instructions
- ).join('\n');
+ ).join('\n') + '\n';
await fs.writeFile(filename, content);
logger.info(`Printed step ${step.id} to ${filename}`);
@@ -80,4 +75,4 @@ export class TestPrinter implements Printer {
printed_at: new Date(),
});
}
-}
\ No newline at end of file
+}