diff --git a/client/cms/.sisyphus/drafts/checkin_logic.md b/client/cms/.sisyphus/drafts/checkin_logic.md
new file mode 100644
index 0000000..606a434
--- /dev/null
+++ b/client/cms/.sisyphus/drafts/checkin_logic.md
@@ -0,0 +1,32 @@
+# Draft: Implement Check-in Logic
+
+## Requirements (User)
+- **Input**: 6-digit number from scanner.
+- **Action**: Call `/event/checkin/submit` (`postEventCheckinSubmit`).
+- **Feedback**: Toaster (success/failure) using `sonner`.
+
+## Research Questions
+1. [Resolved] API Client: `postEventCheckinSubmit` exists.
+2. [Pending] API Parameters: Need to verify `PostEventCheckinSubmitData`.
+3. [Resolved] Toaster Library: `sonner` (`toast.success`, `toast.error`).
+
+## Technical Decisions
+- **Logic Placement**: `CheckinScannerNavContainer`.
+- **State Management**: `useMutation` from `@tanstack/react-query`.
+- **Validation**: Regex `^\d{6}$` for 6-digit number.
+- **Error Handling**: `onError` in mutation -> `toast.error`.
+- **Success Handling**: `onSuccess` in mutation -> `toast.success`.
+
+## Code Snippets
+```typescript
+import { useMutation } from '@tanstack/react-query';
+import { postEventCheckinSubmit } from '@/client/sdk.gen';
+import { toast } from 'sonner';
+
+// In container
+const { mutate } = useMutation({
+ mutationFn: (code: string) => postEventCheckinSubmit({ body: { code } }),
+ onSuccess: () => toast.success('签到成功'),
+ onError: () => toast.error('签到失败'),
+});
+```
diff --git a/client/cms/.sisyphus/notepads/implement-checkin-logic/learnings.md b/client/cms/.sisyphus/notepads/implement-checkin-logic/learnings.md
new file mode 100644
index 0000000..f5a2ace
--- /dev/null
+++ b/client/cms/.sisyphus/notepads/implement-checkin-logic/learnings.md
@@ -0,0 +1,9 @@
+### useCheckinSubmit Hook
+- Created `src/hooks/data/useCheckinSubmit.ts` using `postEventCheckinSubmitMutation` from `@/client/@tanstack/react-query.gen`.
+- Integrated `sonner` for success and error toasts.
+- Followed the pattern from `useJoinEvent.ts`.
+
+### CheckinScannerNav Implementation
+- `CheckinScannerNavView` validation logic implemented with regex `^\d{6}$`.
+- `CheckinScannerNavContainer` connects the hook to the view.
+- Type checking passed with `bun tsc -b`.
diff --git a/client/cms/.sisyphus/plans/implement-checkin-logic.md b/client/cms/.sisyphus/plans/implement-checkin-logic.md
new file mode 100644
index 0000000..ef14632
--- /dev/null
+++ b/client/cms/.sisyphus/plans/implement-checkin-logic.md
@@ -0,0 +1,204 @@
+# Plan: Implement Check-in Logic
+
+## TL;DR
+
+> **Quick Summary**: Connect the scanner to the backend check-in API. When a 6-digit code is scanned, submit it to `/event/checkin/submit`. Show success/error toasts.
+>
+> **Deliverables**:
+> - Updated `CheckinScannerNavContainer` with mutation logic.
+> - Integration with `sonner` for user feedback.
+> - Proper parameter mapping (`checkin_code`).
+>
+> **Estimated Effort**: Short
+> **Parallel Execution**: NO - sequential implementation.
+> **Critical Path**: Implement Mutation → Update View Integration
+
+---
+
+## Context
+
+### Original Request
+"扫码器扫到的如果是6位数字,使用/event/checkin/submit接口进行签到,成功/失败都弹出toaster提示。"
+
+### Interview Summary
+**Key Discussions**:
+- **API**: `postEventCheckinSubmit` is the correct client function.
+- **Parameters**: API expects `checkin_code` in the body.
+- **Input**: "6位数字" implies regex validation `^\d{6}$`.
+- **Feedback**: Use `sonner` (`toast.success`, `toast.error`).
+
+**Metis Review Findings**:
+- **Critical Fix**: Ensure parameter name is `checkin_code`, not `code`.
+- **UX**: Disable scanning while `isPending` to prevent double submissions.
+- **Error Handling**: Use generic "签到失败" for errors unless specific message available.
+
+---
+
+## Work Objectives
+
+### Core Objective
+Make the check-in scanner functional by connecting it to the backend.
+
+### Concrete Deliverables
+- `src/components/checkin/checkin-scanner-nav.container.tsx`: Updated with `useMutation`.
+- `src/components/checkin/checkin-scanner-nav.view.tsx`: Updated to receive `isPending` prop and handle scan events.
+
+### Definition of Done
+- [ ] Scanning "123456" calls API with `{"checkin_code": "123456"}`.
+- [ ] Success response shows "签到成功" toast.
+- [ ] Error response shows "签到失败" toast.
+- [ ] Scanner ignores non-6-digit inputs.
+- [ ] Scanner pauses/ignores input while API is pending.
+
+### Must Have
+- Regex validation: `^\d{6}$`.
+- `checkin_code` parameter mapping.
+- Toaster feedback.
+
+### Must NOT Have (Guardrails)
+- Do NOT change the existing permission logic in the container.
+- Do NOT remove the Dialog wrapping.
+
+---
+
+## Verification Strategy (MANDATORY)
+
+> **UNIVERSAL RULE: ZERO HUMAN INTERVENTION**
+> ALL tasks in this plan MUST be verifiable WITHOUT any human action.
+
+### Test Decision
+- **Infrastructure exists**: YES (Playwright).
+- **Automated tests**: YES (Playwright API mocking).
+
+### Agent-Executed QA Scenarios (MANDATORY)
+
+**Scenario 1: Successful Check-in**
+- **Tool**: Playwright
+- **Steps**:
+ 1. Mock `/event/checkin/submit` to return 200 OK.
+ 2. Simulate scan event with "123456".
+ 3. Assert API called with correct body.
+ 4. Assert "签到成功" toast visible.
+
+**Scenario 2: Failed Check-in**
+- **Tool**: Playwright
+- **Steps**:
+ 1. Mock `/event/checkin/submit` to return 400 Bad Request.
+ 2. Simulate scan event with "123456".
+ 3. Assert "签到失败" toast visible.
+
+**Scenario 3: Invalid Input**
+- **Tool**: Playwright (if view exposes logic) or Unit Test
+- **Steps**:
+ 1. Simulate scan event with "ABC".
+ 2. Assert API NOT called.
+
+---
+
+## Execution Strategy
+
+### Parallel Execution Waves
+
+```
+Wave 1:
+├── Task 1: Create Data Hook
+└── Task 2: Implement Container & View Logic
+```
+
+---
+
+## TODOs
+
+- [x] 1. Create Data Hook
+
+ **What to do**:
+ - Create `src/hooks/data/useCheckinSubmit.ts`.
+ - Import `useMutation` from `@tanstack/react-query`.
+ - Import `postEventCheckinSubmitMutation` from `@/client/@tanstack/react-query.gen`.
+ - Import `toast` from `sonner`.
+ - Export `useCheckinSubmit` hook that returns the mutation.
+ - Use `...postEventCheckinSubmitMutation()` pattern.
+ - On success: `toast.success('签到成功')`.
+ - On error: `toast.error('签到失败')`.
+
+ **Recommended Agent Profile**:
+ - **Category**: `quick`
+ - **Skills**: [`frontend-ui-ux`]
+
+ **Parallelization**:
+ - **Can Run In Parallel**: YES
+ - **Parallel Group**: Wave 1
+
+ **References**:
+ - `src/hooks/data/useJoinEvent.ts` (Pattern reference)
+ - `src/client/@tanstack/react-query.gen.ts`
+
+ **Acceptance Criteria**:
+ - [ ] Hook uses `@hey-api` pattern.
+ - [ ] Toasts are configured.
+
+- [x] 2. Implement Container & View Logic
+
+ **What to do**:
+ - Update `src/components/checkin/checkin-scanner-nav.container.tsx`:
+ - Import `useCheckinSubmit` from `@/hooks/data/useCheckinSubmit`.
+ - Use the hook to get `mutate` and `isPending`.
+ - Pass `handleScan` (wrapper calling mutate with `{ body: { checkin_code: code } }`) and `isPending` to View.
+ - Update `src/components/checkin/checkin-scanner-nav.view.tsx`:
+ - Accept `onScan` and `isPending` props.
+ - Inside internal `handleScan`, check regex `^\d{6}$`.
+ - If valid and !isPending, call prop `onScan`.
+
+ **Recommended Agent Profile**:
+ - **Category**: `visual-engineering`
+ - **Skills**: [`frontend-ui-ux`]
+
+ **Parallelization**:
+ - **Can Run In Parallel**: YES
+ - **Parallel Group**: Wave 1
+ - **References**:
+ - `src/hooks/data/useCheckinSubmit.ts` (Dependency)
+
+ **Acceptance Criteria**:
+ - [ ] Container uses the new hook.
+ - [ ] View logic validates regex.
+
+- [ ] 2. Update Playwright Verification
+
+ **What to do**:
+ - Update `tests/checkin-scanner.spec.ts`.
+ - Add test case for successful check-in (mock API success).
+ - Add test case for failed check-in (mock API failure).
+ - Verify toaster appearance.
+
+ **Recommended Agent Profile**:
+ - **Category**: `quick`
+ - **Skills**: [`playwright`]
+
+ **Parallelization**:
+ - **Can Run In Parallel**: NO
+ - **Parallel Group**: Wave 1
+ - **Blocked By**: Task 1
+
+ **References**:
+ - `tests/checkin-scanner.spec.ts`
+
+ **Acceptance Criteria**:
+ - [ ] Tests pass.
+
+ **Agent-Executed QA Scenarios**:
+ ```
+ Scenario: Run Updated Tests
+ Tool: Bash
+ Steps:
+ 1. npx playwright test tests/checkin-scanner.spec.ts
+ ```
+
+---
+
+## Success Criteria
+
+### Final Checklist
+- [ ] API integration complete.
+- [ ] Regex validation matches `^\d{6}$`.
+- [ ] User feedback (toasts) functional.
diff --git a/client/cms/src/components/checkin/checkin-scanner-nav.container.tsx b/client/cms/src/components/checkin/checkin-scanner-nav.container.tsx
index 1e1e821..955557f 100644
--- a/client/cms/src/components/checkin/checkin-scanner-nav.container.tsx
+++ b/client/cms/src/components/checkin/checkin-scanner-nav.container.tsx
@@ -1,12 +1,19 @@
import { useUserInfo } from '@/hooks/data/useUserInfo';
+import { useCheckinSubmit } from '@/hooks/data/useCheckinSubmit';
import { CheckinScannerNavView } from './checkin-scanner-nav.view';
export function CheckinScannerNavContainer() {
const { data } = useUserInfo();
+ const { mutate, isPending } = useCheckinSubmit();
if ((data.data?.permission_level ?? 0) <= 20) {
return null;
}
- return ;
+ return (
+ mutate({ body: { checkin_code: code } })}
+ isPending={isPending}
+ />
+ );
}
diff --git a/client/cms/src/components/checkin/checkin-scanner-nav.view.tsx b/client/cms/src/components/checkin/checkin-scanner-nav.view.tsx
index dee5b18..0e46a72 100644
--- a/client/cms/src/components/checkin/checkin-scanner-nav.view.tsx
+++ b/client/cms/src/components/checkin/checkin-scanner-nav.view.tsx
@@ -4,11 +4,22 @@ import { Dialog, DialogTrigger } from '@/components/ui/dialog';
import { SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar';
import { CheckinScannerDialogView } from './checkin-scanner.dialog.view';
-export function CheckinScannerNavView() {
+interface CheckinScannerNavViewProps {
+ onScan: (code: string) => void;
+ isPending: boolean;
+}
+
+export function CheckinScannerNavView({ onScan, isPending }: CheckinScannerNavViewProps) {
const [open, setOpen] = useState(false);
const handleScan = (value: string) => {
- console.log('Scanned:', value);
+ if (isPending) return;
+
+ if (!/^\d{6}$/.test(value)) {
+ return;
+ }
+
+ onScan(value);
setOpen(false);
};
diff --git a/client/cms/src/hooks/data/useCheckinSubmit.ts b/client/cms/src/hooks/data/useCheckinSubmit.ts
new file mode 100644
index 0000000..e894680
--- /dev/null
+++ b/client/cms/src/hooks/data/useCheckinSubmit.ts
@@ -0,0 +1,15 @@
+import { useMutation } from '@tanstack/react-query';
+import { toast } from 'sonner';
+import { postEventCheckinSubmitMutation } from '@/client/@tanstack/react-query.gen';
+
+export function useCheckinSubmit() {
+ return useMutation({
+ ...postEventCheckinSubmitMutation(),
+ onSuccess: () => {
+ toast.success('签到成功');
+ },
+ onError: () => {
+ toast.error('签到失败');
+ },
+ });
+}