18 KiB
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 stepsclient/src/pages/info/ui/sections/DeliverySection.tsx— 3 delivery option cards in Gridclient/src/pages/info/ui/sections/PaymentSection.tsx— List of payment methodsclient/src/pages/info/ui/sections/ReturnsSection.tsx— Returns & warranty Paper blocks
Modified
client/src/pages/info/ui/InfoPage.tsx— Rewrite as static container without useQueryclient/src/pages/admin-layout/ui/AdminLayoutPage.tsx— Remove info page nav item and importserver/src/routes/api.js— Remove import and registration callserver/prisma/schema.prisma— Remove InfoPageBlock model
Deleted
client/src/pages/admin-info/ui/AdminInfoPage.tsxclient/src/pages/admin-info/index.tsclient/src/entities/info/api/info-page-api.tsclient/src/entities/info/model/types.tsclient/src/entities/info/index.tsserver/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
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
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
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
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
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
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
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
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
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
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
rm client/src/pages/admin-info/ui/AdminInfoPage.tsx
rm client/src/pages/admin-info/index.ts
- Step 2: Commit
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
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
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
// 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:
import { AdminInfoPage } from "@/pages/admin-info";
- Step 2: Remove FileText from lucide-react import
In line 18, change:
import {
Bell,
FileText,
Image,
LayoutGrid,
ListOrdered,
MessageSquare,
Store,
Users,
} from "lucide-react";
to:
import {
Bell,
Image,
LayoutGrid,
ListOrdered,
MessageSquare,
Store,
Users,
} from "lucide-react";
- Step 3: Remove nav item
Remove the nav item entry (line 64):
{ to: '/admin/info', label: 'Инфо-страница', icon: <FileText /> },
- Step 4: Remove route
Remove the route line 192:
<Route path="info" element={<AdminInfoPage />} />
- Step 5: Commit
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
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:
import { registerInfoPageRoutes } from "./api/info-page.js";
Remove the call line 21:
await registerInfoPageRoutes(fastify);
- Step 3: Commit
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:
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
cd server && npm run db:migrate
Expected: Prisma creates a new migration dropping the InfoPageBlock table.
- Step 3: Commit
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
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
cd client && npm run lint
Expected: no errors.
- Step 3: Run client format check
cd client && npm run format:check
Expected: all files formatted.
- Step 4: Run client tests
cd client && npm test
Expected: all tests pass.
- Step 5: Build client
cd client && npm run build
Expected: tsc + Vite build succeed with no errors.
- Step 6: Commit if any fixes
git add -A
git commit -m "chore: lint and build fixes after info page migration"