Files
shop-server/docs/superpowers/plans/2026-05-19-info-page-static.md
T
2026-05-19 15:32:45 +05:00

637 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Static Info Page Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Replace admin-managed dynamic InfoPageBlock CRUD with a hardcoded static React page featuring process schemas, delivery cards, and payment info.
**Architecture:** New `InfoPage.tsx` container composes four hardcoded section components (no API calls, no DB reads). All admin CRUD files, server routes, Prisma model, and entity layer are removed.
**Tech Stack:** React + TypeScript + MUI, lucide-react icons.
---
## File Structure
### Created
- `client/src/pages/info/ui/sections/HowToOrderSection.tsx` — Stepper with 5 purchase steps
- `client/src/pages/info/ui/sections/DeliverySection.tsx` — 3 delivery option cards in Grid
- `client/src/pages/info/ui/sections/PaymentSection.tsx` — List of payment methods
- `client/src/pages/info/ui/sections/ReturnsSection.tsx` — Returns & warranty Paper blocks
### Modified
- `client/src/pages/info/ui/InfoPage.tsx` — Rewrite as static container without useQuery
- `client/src/pages/admin-layout/ui/AdminLayoutPage.tsx` — Remove info page nav item and import
- `server/src/routes/api.js` — Remove import and registration call
- `server/prisma/schema.prisma` — Remove InfoPageBlock model
### Deleted
- `client/src/pages/admin-info/ui/AdminInfoPage.tsx`
- `client/src/pages/admin-info/index.ts`
- `client/src/entities/info/api/info-page-api.ts`
- `client/src/entities/info/model/types.ts`
- `client/src/entities/info/index.ts`
- `server/src/routes/api/info-page.js`
---
### Task 1: Create HowToOrderSection
**Files:**
- Create: `client/src/pages/info/ui/sections/HowToOrderSection.tsx`
- [ ] **Step 1: Write the component**
```tsx
import Paper from "@mui/material/Paper";
import Step from "@mui/material/Step";
import StepContent from "@mui/material/StepContent";
import StepLabel from "@mui/material/StepLabel";
import Stepper from "@mui/material/Stepper";
import Typography from "@mui/material/Typography";
import {
CheckCircle,
ClipboardList,
Mail,
ShoppingCart,
Truck,
} from "lucide-react";
const steps = [
{
label: "Выберите товары",
icon: <ShoppingCart size={20} />,
text: "Найдите нужные изделия в каталоге и добавьте их в корзину. Вы можете выбрать несколько товаров от разных мастеров — все они соберутся в одном заказе.",
},
{
label: "Проверьте корзину",
icon: <ClipboardList size={20} />,
text: "Перейдите в корзину и проверьте состав заказа: названия товаров, количество и итоговую сумму. Здесь же можно изменить количество или удалить позиции.",
},
{
label: "Укажите контакты и адрес",
icon: <Mail size={20} />,
text: "Заполните имя, телефон и email для связи. Укажите адрес доставки — город, улицу, дом и квартиру. Эти данные нужны для расчёта стоимости и сроков.",
},
{
label: "Выберите доставку и оплату",
icon: <Truck size={20} />,
text: "Выберите способ доставки: самовывоз, курьер или почта/СДЭК. Затем укажите способ оплаты: картой онлайн или при получении.",
},
{
label: "Подтвердите заказ",
icon: <CheckCircle size={20} />,
text: "Проверьте все данные ещё раз и нажмите «Оформить заказ». После этого мастер получит уведомление и начнёт подготовку вашего изделия.",
},
];
export function HowToOrderSection() {
return (
<Paper variant="outlined" sx={{ p: 3, borderRadius: 2 }}>
<Typography variant="h5" gutterBottom>
Как оформить заказ
</Typography>
<Stepper orientation="vertical" activeStep={-1}>
{steps.map((step, idx) => (
<Step key={idx} completed={false}>
<StepLabel StepIconComponent={() => step.icon}>
{step.label}
</StepLabel>
<StepContent>
<Typography color="text.secondary">{step.text}</Typography>
</StepContent>
</Step>
))}
</Stepper>
</Paper>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/info/ui/sections/HowToOrderSection.tsx
git commit -m "feat: add HowToOrderSection with purchase step stepper"
```
---
### Task 2: Create DeliverySection
**Files:**
- Create: `client/src/pages/info/ui/sections/DeliverySection.tsx`
- [ ] **Step 1: Write the component**
```tsx
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { Package, Store, Truck } from "lucide-react";
import { PICKUP_ADDRESS_FULL } from "@/shared/constants/pickup-point";
const deliveries = [
{
title: "Самовывоз",
icon: <Store size={28} />,
lines: [
"Бесплатно.",
PICKUP_ADDRESS_FULL,
"Перед визитом согласуем время — чтобы заказ точно был готов к выдаче.",
],
},
{
title: "Курьер по городу",
icon: <Truck size={28} />,
lines: [
"Доставка в пределах города.",
"Сроки и стоимость зависят от адреса и веса заказа.",
"Мастер свяжется с вами для уточнения деталей после оформления.",
],
},
{
title: "Почта / СДЭК",
icon: <Package size={28} />,
lines: [
"Отправка в другие города.",
"Каждому заказу присваивается трек-номер для отслеживания.",
"Стоимость рассчитывается по тарифу перевозчика при оформлении.",
],
},
];
export function DeliverySection() {
return (
<Paper variant="outlined" sx={{ p: 3, borderRadius: 2 }}>
<Typography variant="h5" gutterBottom>
Доставка
</Typography>
<Grid container spacing={2}>
{deliveries.map((d) => (
<Grid key={d.title} size={{ xs: 12, sm: 6, md: 4 }}>
<Paper
variant="outlined"
sx={{ p: 2, borderRadius: 2, height: "100%" }}
>
<Stack spacing={1.5}>
<Stack
direction="row"
spacing={1}
sx={{ alignItems: "center" }}
>
{d.icon}
<Typography variant="h6">{d.title}</Typography>
</Stack>
{d.lines.map((line, i) => (
<Typography key={i} variant="body2" color="text.secondary">
{line}
</Typography>
))}
</Stack>
</Paper>
</Grid>
))}
</Grid>
</Paper>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/info/ui/sections/DeliverySection.tsx
git commit -m "feat: add DeliverySection with pickup, courier, and postal cards"
```
---
### Task 3: Create PaymentSection
**Files:**
- Create: `client/src/pages/info/ui/sections/PaymentSection.tsx`
- [ ] **Step 1: Write the component**
```tsx
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import { Banknote, CreditCard } from "lucide-react";
const methods = [
{
icon: <CreditCard size={22} />,
primary: "Банковская карта онлайн",
secondary:
"Оплата картой Visa, Mastercard или МИР сразу при оформлении заказа.",
},
{
icon: <Banknote size={22} />,
primary: "Оплата при получении",
secondary: "Оплата наличными или картой при получении заказа.",
},
];
export function PaymentSection() {
return (
<Paper variant="outlined" sx={{ p: 3, borderRadius: 2 }}>
<Typography variant="h5" gutterBottom>
Оплата
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
Оплата происходит после подтверждения заказа мастером. Вы получите
уведомление, когда заказ будет подтверждён и готов к оплате.
</Typography>
<List disablePadding>
{methods.map((m) => (
<ListItem key={m.primary} disableGutters>
<ListItemIcon sx={{ minWidth: 40 }}>{m.icon}</ListItemIcon>
<ListItemText primary={m.primary} secondary={m.secondary} />
</ListItem>
))}
</List>
</Paper>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/info/ui/sections/PaymentSection.tsx
git commit -m "feat: add PaymentSection with card and cash methods"
```
---
### Task 4: Create ReturnsSection
**Files:**
- Create: `client/src/pages/info/ui/sections/ReturnsSection.tsx`
- [ ] **Step 1: Write the component**
```tsx
import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
export function ReturnsSection() {
return (
<Paper variant="outlined" sx={{ p: 3, borderRadius: 2 }}>
<Typography variant="h5" gutterBottom>
Возврат и гарантии
</Typography>
<Stack spacing={2}>
<Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }} gutterBottom>
Возврат
</Typography>
<Typography variant="body2" color="text.secondary">
Если товар не соответствует описанию или имеет производственный
дефект, свяжитесь с нами в течение 7 дней после получения. Мы
заменим изделие на аналогичное или вернём деньги. Возврат товара
надлежащего качества возможен в течение 14 дней, если изделие не
было в употреблении и сохранён его товарный вид.
</Typography>
</Paper>
<Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
<Typography variant="subtitle1" sx={{ fontWeight: 600 }} gutterBottom>
Гарантия качества
</Typography>
<Typography variant="body2" color="text.secondary">
Мы отвечаем за качество каждого изделия ручной работы. Все дефекты,
возникшие не по вине покупателя, устраняются или компенсируются
заменой изделия. Если у вас возникли вопросы по качеству напишите
нам, и мы решим проблему в кратчайшие сроки.
</Typography>
</Paper>
</Stack>
</Paper>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/info/ui/sections/ReturnsSection.tsx
git commit -m "feat: add ReturnsSection with return and warranty blocks"
```
---
### Task 5: Rewrite InfoPage as static container
**Files:**
- Modify: `client/src/pages/info/ui/InfoPage.tsx`
- [ ] **Step 1: Rewrite InfoPage.tsx**
```tsx
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { DeliverySection } from "./sections/DeliverySection";
import { HowToOrderSection } from "./sections/HowToOrderSection";
import { PaymentSection } from "./sections/PaymentSection";
import { ReturnsSection } from "./sections/ReturnsSection";
export function InfoPage() {
return (
<Box>
<Typography variant="h4" gutterBottom>
Информация для покупателей
</Typography>
<Typography color="text.secondary" sx={{ mb: 3 }}>
Как оформить заказ, как проходит доставка, оплата и другие важные
детали.
</Typography>
<Stack spacing={3}>
<HowToOrderSection />
<DeliverySection />
<PaymentSection />
<ReturnsSection />
</Stack>
</Box>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/info/ui/InfoPage.tsx
git commit -m "feat: rewrite InfoPage as static container with section components"
```
---
### Task 6: Delete admin info page
**Files:**
- Delete: `client/src/pages/admin-info/ui/AdminInfoPage.tsx`
- Delete: `client/src/pages/admin-info/index.ts`
- [ ] **Step 1: Delete files**
```bash
rm client/src/pages/admin-info/ui/AdminInfoPage.tsx
rm client/src/pages/admin-info/index.ts
```
- [ ] **Step 2: Commit**
```bash
git add client/src/pages/admin-info/
git commit -m "feat: remove admin info page CRUD"
```
---
### Task 7: Delete entities/info
**Files:**
- Delete: `client/src/entities/info/api/info-page-api.ts`
- Delete: `client/src/entities/info/model/types.ts`
- Delete: `client/src/entities/info/index.ts`
- [ ] **Step 1: Delete files**
```bash
rm client/src/entities/info/api/info-page-api.ts
rm client/src/entities/info/model/types.ts
rm client/src/entities/info/index.ts
```
- [ ] **Step 2: Commit**
```bash
git add client/src/entities/info/
git commit -m "feat: remove info entity (admin CRUD layer)"
```
---
### Task 8: Clean up AdminLayoutPage
**Files:**
- Modify: `client/src/pages/admin-layout/ui/AdminLayoutPage.tsx`
- [ ] **Step 1: Remove import**
```tsx
// REMOVE line 23:
import { AdminInfoPage } from "@/pages/admin-info";
```
Execute this edit: In `client/src/pages/admin-layout/ui/AdminLayoutPage.tsx`, remove the import line:
```tsx
import { AdminInfoPage } from "@/pages/admin-info";
```
- [ ] **Step 2: Remove FileText from lucide-react import**
In line 18, change:
```tsx
import {
Bell,
FileText,
Image,
LayoutGrid,
ListOrdered,
MessageSquare,
Store,
Users,
} from "lucide-react";
```
to:
```tsx
import {
Bell,
Image,
LayoutGrid,
ListOrdered,
MessageSquare,
Store,
Users,
} from "lucide-react";
```
- [ ] **Step 3: Remove nav item**
Remove the nav item entry (line 64):
```tsx
{ to: '/admin/info', label: 'Инфо-страница', icon: <FileText /> },
```
- [ ] **Step 4: Remove route**
Remove the route line 192:
```tsx
<Route path="info" element={<AdminInfoPage />} />
```
- [ ] **Step 5: Commit**
```bash
git add client/src/pages/admin-layout/ui/AdminLayoutPage.tsx
git commit -m "feat: remove info page from admin navigation and routes"
```
---
### Task 9: Delete server info-page routes
**Files:**
- Delete: `server/src/routes/api/info-page.js`
- Modify: `server/src/routes/api.js`
- [ ] **Step 1: Delete the routes file**
```bash
rm server/src/routes/api/info-page.js
```
- [ ] **Step 2: Clean up api.js**
In `server/src/routes/api.js`:
Remove the import line 10:
```js
import { registerInfoPageRoutes } from "./api/info-page.js";
```
Remove the call line 21:
```js
await registerInfoPageRoutes(fastify);
```
- [ ] **Step 3: Commit**
```bash
git add server/src/routes/api/info-page.js server/src/routes/api.js
git commit -m "feat: remove server info-page routes"
```
---
### Task 10: Remove InfoPageBlock model from Prisma schema
**Files:**
- Modify: `server/prisma/schema.prisma`
- [ ] **Step 1: Remove model from schema**
Remove lines 262-273 from `server/prisma/schema.prisma`:
```prisma
model InfoPageBlock {
id String @id @default(cuid())
key String @unique
title String
body String
sort Int @default(0)
published Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([published, sort])
}
```
Also remove the blank line before it (line 261).
- [ ] **Step 2: Run migration**
```bash
cd server && npm run db:migrate
```
Expected: Prisma creates a new migration dropping the `InfoPageBlock` table.
- [ ] **Step 3: Commit**
```bash
git add server/prisma/schema.prisma server/prisma/migrations/
git commit -m "feat: remove InfoPageBlock model from Prisma schema"
```
---
### Task 11: Verify build and lint
- [ ] **Step 1: Run server tests**
```bash
cd server && npm test
```
Expected: all tests pass (no info-page tests exist, but other tests should still pass after removing routes).
- [ ] **Step 2: Run client lint**
```bash
cd client && npm run lint
```
Expected: no errors.
- [ ] **Step 3: Run client format check**
```bash
cd client && npm run format:check
```
Expected: all files formatted.
- [ ] **Step 4: Run client tests**
```bash
cd client && npm test
```
Expected: all tests pass.
- [ ] **Step 5: Build client**
```bash
cd client && npm run build
```
Expected: tsc + Vite build succeed with no errors.
- [ ] **Step 6: Commit if any fixes**
```bash
git add -A
git commit -m "chore: lint and build fixes after info page migration"
```