This commit is contained in:
Kirill
2026-05-26 12:30:09 +05:00
parent e092299a11
commit c01070cb09
5 changed files with 119 additions and 92 deletions
+46 -36
View File
@@ -119,7 +119,6 @@
"version": "7.29.7", "version": "7.29.7",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.7", "@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7", "@babel/generator": "^7.29.7",
@@ -419,7 +418,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
}, },
@@ -441,7 +439,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -499,7 +496,6 @@
"node_modules/@dicebear/core": { "node_modules/@dicebear/core": {
"version": "9.4.2", "version": "9.4.2",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/json-schema": "^7.0.15" "@types/json-schema": "^7.0.15"
}, },
@@ -617,6 +613,29 @@
"@dicebear/core": "^9.0.0" "@dicebear/core": "^9.0.0"
} }
}, },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": { "node_modules/@emnapi/wasi-threads": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -674,7 +693,6 @@
"node_modules/@emotion/react": { "node_modules/@emotion/react": {
"version": "11.14.0", "version": "11.14.0",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5", "@emotion/babel-plugin": "^11.13.5",
@@ -712,7 +730,6 @@
"node_modules/@emotion/styled": { "node_modules/@emotion/styled": {
"version": "11.14.1", "version": "11.14.1",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5", "@emotion/babel-plugin": "^11.13.5",
@@ -1333,6 +1350,17 @@
"@floating-ui/utils": "^0.2.11" "@floating-ui/utils": "^0.2.11"
} }
}, },
"node_modules/@floating-ui/dom": {
"version": "1.7.6",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"@floating-ui/core": "^1.7.5",
"@floating-ui/utils": "^0.2.11"
}
},
"node_modules/@floating-ui/utils": { "node_modules/@floating-ui/utils": {
"version": "0.2.11", "version": "0.2.11",
"license": "MIT", "license": "MIT",
@@ -1551,7 +1579,6 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-9.0.1.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.0.1.tgz",
"integrity": "sha512-voyCpeUxcSWLN7KPZuq0pGCIt726T9K6kiVM3XUcywZDAlZSarLHaUxJVQpospbjjOzN53hwyjo8s6KoWl6utw==", "integrity": "sha512-voyCpeUxcSWLN7KPZuq0pGCIt726T9K6kiVM3XUcywZDAlZSarLHaUxJVQpospbjjOzN53hwyjo8s6KoWl6utw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.29.2", "@babel/runtime": "^7.29.2",
"@mui/core-downloads-tracker": "^9.0.1", "@mui/core-downloads-tracker": "^9.0.1",
@@ -2440,6 +2467,7 @@
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"dequal": "^2.0.3" "dequal": "^2.0.3"
} }
@@ -2520,7 +2548,6 @@
"node_modules/@tiptap/core": { "node_modules/@tiptap/core": {
"version": "3.23.6", "version": "3.23.6",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ueberdosis" "url": "https://github.com/sponsors/ueberdosis"
@@ -2711,7 +2738,6 @@
"node_modules/@tiptap/extension-list": { "node_modules/@tiptap/extension-list": {
"version": "3.23.6", "version": "3.23.6",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ueberdosis" "url": "https://github.com/sponsors/ueberdosis"
@@ -2812,7 +2838,6 @@
"node_modules/@tiptap/extensions": { "node_modules/@tiptap/extensions": {
"version": "3.23.6", "version": "3.23.6",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ueberdosis" "url": "https://github.com/sponsors/ueberdosis"
@@ -2825,7 +2850,6 @@
"node_modules/@tiptap/pm": { "node_modules/@tiptap/pm": {
"version": "3.23.6", "version": "3.23.6",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"prosemirror-changeset": "^2.3.0", "prosemirror-changeset": "^2.3.0",
"prosemirror-commands": "^1.6.2", "prosemirror-commands": "^1.6.2",
@@ -2918,7 +2942,8 @@
"node_modules/@types/aria-query": { "node_modules/@types/aria-query": {
"version": "5.0.4", "version": "5.0.4",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/@types/chai": { "node_modules/@types/chai": {
"version": "5.2.3", "version": "5.2.3",
@@ -2951,7 +2976,6 @@
"version": "24.12.4", "version": "24.12.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
@@ -2967,7 +2991,6 @@
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.2.15", "version": "19.2.15",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.2.2" "csstype": "^3.2.2"
} }
@@ -2975,7 +2998,6 @@
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "19.2.3", "version": "19.2.3",
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
@@ -3002,7 +3024,6 @@
"version": "8.59.4", "version": "8.59.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/scope-manager": "8.59.4",
"@typescript-eslint/types": "8.59.4", "@typescript-eslint/types": "8.59.4",
@@ -3171,7 +3192,6 @@
"version": "8.59.4", "version": "8.59.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.9.1", "@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/scope-manager": "8.59.4",
@@ -3684,7 +3704,6 @@
"version": "8.16.0", "version": "8.16.0",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -3729,6 +3748,7 @@
"version": "5.0.1", "version": "5.0.1",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@@ -4839,6 +4859,7 @@
"version": "2.0.3", "version": "2.0.3",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@@ -4865,7 +4886,8 @@
"node_modules/dom-accessibility-api": { "node_modules/dom-accessibility-api": {
"version": "0.5.16", "version": "0.5.16",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/dom-helpers": { "node_modules/dom-helpers": {
"version": "5.2.1", "version": "5.2.1",
@@ -4904,7 +4926,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=11.0.0" "node": ">=11.0.0"
} }
@@ -5130,7 +5151,6 @@
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"esbuild": "bin/esbuild" "esbuild": "bin/esbuild"
}, },
@@ -5190,7 +5210,6 @@
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -5249,7 +5268,6 @@
"version": "10.1.8", "version": "10.1.8",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
@@ -5381,7 +5399,6 @@
"version": "4.16.2", "version": "4.16.2",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@package-json/types": "^0.0.12", "@package-json/types": "^0.0.12",
"@typescript-eslint/types": "^8.56.0", "@typescript-eslint/types": "^8.56.0",
@@ -7167,6 +7184,7 @@
"version": "1.5.0", "version": "1.5.0",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"lz-string": "bin/bin.js" "lz-string": "bin/bin.js"
} }
@@ -7182,7 +7200,6 @@
"node_modules/maplibre-gl": { "node_modules/maplibre-gl": {
"version": "5.24.0", "version": "5.24.0",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2",
"@mapbox/point-geometry": "^1.1.0", "@mapbox/point-geometry": "^1.1.0",
@@ -7740,7 +7757,6 @@
"version": "3.8.3", "version": "3.8.3",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@@ -7766,6 +7782,7 @@
"version": "27.5.1", "version": "27.5.1",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"ansi-regex": "^5.0.1", "ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0", "ansi-styles": "^5.0.0",
@@ -7779,6 +7796,7 @@
"version": "5.2.0", "version": "5.2.0",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@@ -7789,7 +7807,8 @@
"node_modules/pretty-format/node_modules/react-is": { "node_modules/pretty-format/node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
@@ -7935,7 +7954,6 @@
"node_modules/react": { "node_modules/react": {
"version": "19.2.6", "version": "19.2.6",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -7943,7 +7961,6 @@
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "19.2.6", "version": "19.2.6",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -9127,7 +9144,6 @@
"version": "4.0.4", "version": "4.0.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -9318,7 +9334,6 @@
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -9530,7 +9545,6 @@
"version": "8.0.14", "version": "8.0.14",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"picomatch": "^4.0.4", "picomatch": "^4.0.4",
@@ -9644,7 +9658,6 @@
"version": "4.0.4", "version": "4.0.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -9884,7 +9897,6 @@
"version": "4.0.4", "version": "4.0.4",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -9896,7 +9908,6 @@
"version": "7.3.3", "version": "7.3.3",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.27.0", "esbuild": "^0.27.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
@@ -10198,7 +10209,6 @@
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
@@ -59,7 +59,7 @@ export function GalleryImagePicker({
return ( return (
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="sm"> <Dialog open={open} onClose={handleClose} fullWidth maxWidth="sm">
<DialogTitle>Изображения из галереи</DialogTitle> <DialogTitle>Изображения из галереи</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
{galleryQuery.isLoading && <Typography color="text.secondary">Загрузка списка</Typography>} {galleryQuery.isLoading && <Typography color="text.secondary">Загрузка списка</Typography>}
{galleryQuery.isError && <Alert severity="error">Не удалось загрузить галерею. Попробуйте ещё раз.</Alert>} {galleryQuery.isError && <Alert severity="error">Не удалось загрузить галерею. Попробуйте ещё раз.</Alert>}
{galleryQuery.data?.items.length === 0 && !galleryQuery.isLoading && ( {galleryQuery.data?.items.length === 0 && !galleryQuery.isLoading && (
@@ -13,6 +13,7 @@ import ToggleButton from '@mui/material/ToggleButton'
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { Grid3x3, List } from 'lucide-react'
import { import {
deleteGalleryImage, deleteGalleryImage,
fetchAdminGallery, fetchAdminGallery,
@@ -24,7 +25,6 @@ import type { GalleryImageItem } from '@/entities/gallery'
import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits' import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys' import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
import type { AxiosError } from 'axios' import type { AxiosError } from 'axios'
import { Grid3x3, List } from 'lucide-react'
function getApiErrorMessage(error: unknown): string | null { function getApiErrorMessage(error: unknown): string | null {
const e = error as AxiosError<{ error?: string }> const e = error as AxiosError<{ error?: string }>
@@ -197,12 +197,7 @@ export function AdminGalleryPage() {
}} }}
/> />
</Button> </Button>
<ToggleButtonGroup <ToggleButtonGroup value={viewMode} exclusive onChange={(_, v) => v && setViewMode(v)} size="small">
value={viewMode}
exclusive
onChange={(_, v) => v && setViewMode(v)}
size="small"
>
<ToggleButton value="grid" aria-label="Сетка"> <ToggleButton value="grid" aria-label="Сетка">
<Grid3x3 size={16} /> <Grid3x3 size={16} />
</ToggleButton> </ToggleButton>
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react' import { useMemo, useState } from 'react'
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward' import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward' import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined' import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'
@@ -21,36 +21,17 @@ import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
type SlideDraft = { galleryImageId: string; caption: string; textColor: string } type SlideDraft = { galleryImageId: string; caption: string; textColor: string }
export function AdminSliderPage() { function SliderEditor({
initialSlides,
galleryItems,
}: {
initialSlides: SlideDraft[]
galleryItems: GalleryImageItem[]
}) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [sliderDraft, setSliderDraft] = useState<SlideDraft[]>(initialSlides)
const sliderQuery = useQuery({
queryKey: ['admin', 'catalog-slider'],
queryFn: fetchAdminCatalogSlider,
})
const galleryQuery = useQuery({
queryKey: ['admin', 'gallery'],
queryFn: fetchAdminGallery,
})
const [sliderDraft, setSliderDraft] = useState<SlideDraft[]>([])
const [pickOpen, setPickOpen] = useState(false) const [pickOpen, setPickOpen] = useState(false)
useEffect(() => {
if (sliderQuery.isSuccess && sliderDraft.length === 0) {
setSliderDraft(
sliderQuery.data.slides.map((s) => ({
galleryImageId: s.galleryImageId,
caption: s.caption,
textColor: s.textColor || '#ffffff',
})),
)
}
}, [sliderQuery.isSuccess, sliderQuery.dataUpdatedAt])
const galleryItems: GalleryImageItem[] = galleryQuery.data?.items ?? []
const usedIds = new Set(sliderDraft.map((s) => s.galleryImageId)) const usedIds = new Set(sliderDraft.map((s) => s.galleryImageId))
const pickCandidates = galleryItems.filter((i) => !usedIds.has(i.id) && i.isResized) const pickCandidates = galleryItems.filter((i) => !usedIds.has(i.id) && i.isResized)
@@ -88,24 +69,8 @@ export function AdminSliderPage() {
}) })
} }
if (sliderQuery.isLoading || galleryQuery.isLoading) {
return <Typography color="text.secondary">Загрузка</Typography>
}
if (sliderQuery.isError) {
return <Typography color="error">Не удалось загрузить слайдер.</Typography>
}
return ( return (
<Box> <>
<Typography variant="h4" gutterBottom>
Слайдер
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Изображения для карусели на главной странице. Сначала загрузите фото в Галерею и обработайте их (Resize), затем
добавьте в слайдер. Порядок строк = порядок показа.
</Typography>
<Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}> <Paper variant="outlined" sx={{ p: 2, borderRadius: 2 }}>
<Stack spacing={1.5} sx={{ mb: 2 }}> <Stack spacing={1.5} sx={{ mb: 2 }}>
{sliderDraft.length === 0 && ( {sliderDraft.length === 0 && (
@@ -236,6 +201,51 @@ export function AdminSliderPage() {
<Button onClick={() => setPickOpen(false)}>Закрыть</Button> <Button onClick={() => setPickOpen(false)}>Закрыть</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
</>
)
}
export function AdminSliderPage() {
const sliderQuery = useQuery({
queryKey: ['admin', 'catalog-slider'],
queryFn: fetchAdminCatalogSlider,
})
const galleryQuery = useQuery({
queryKey: ['admin', 'gallery'],
queryFn: fetchAdminGallery,
})
const galleryItems: GalleryImageItem[] = galleryQuery.data?.items ?? []
const initialSlides = useMemo<SlideDraft[]>(() => {
if (!sliderQuery.isSuccess) return []
return sliderQuery.data.slides.map((s) => ({
galleryImageId: s.galleryImageId,
caption: s.caption,
textColor: s.textColor || '#ffffff',
}))
}, [sliderQuery.isSuccess, sliderQuery.data?.slides])
if (sliderQuery.isLoading || galleryQuery.isLoading) {
return <Typography color="text.secondary">Загрузка</Typography>
}
if (sliderQuery.isError) {
return <Typography color="error">Не удалось загрузить слайдер.</Typography>
}
return (
<Box>
<Typography variant="h4" gutterBottom>
Слайдер
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Изображения для карусели на главной странице. Сначала загрузите фото в Галерею и обработайте их (Resize), затем
добавьте в слайдер. Порядок строк = порядок показа.
</Typography>
<SliderEditor key={sliderQuery.dataUpdatedAt} initialSlides={initialSlides} galleryItems={galleryItems} />
</Box> </Box>
) )
} }
+15 -3
View File
@@ -13,12 +13,24 @@ import { AuthForgotForm } from '@/features/auth-forgot'
import { OAuthButtons } from '@/features/auth-oauth' import { OAuthButtons } from '@/features/auth-oauth'
import { AuthPasswordForm } from '@/features/auth-password' import { AuthPasswordForm } from '@/features/auth-password'
import { $user } from '@/shared/model/auth' import { $user } from '@/shared/model/auth'
import { useThemeController } from '@/app/providers/theme-controller' import type { ColorScheme } from '@/shared/model/theme'
import { BearLogo } from '@/shared/ui/BearLogo' import { BearLogo } from '@/shared/ui/BearLogo'
function readStoredScheme(): ColorScheme {
try {
const raw = localStorage.getItem('craftshop_theme')
if (!raw) return 'craft'
const parsed = JSON.parse(raw)
const scheme = parsed?.scheme
return scheme === 'forest' || scheme === 'ocean' || scheme === 'berry' ? scheme : 'craft'
} catch {
return 'craft'
}
}
export function AuthPage() { export function AuthPage() {
const theme = useTheme() const theme = useTheme()
const { scheme } = useThemeController() const scheme = readStoredScheme()
const [message, setMessage] = useState<string | null>(null) const [message, setMessage] = useState<string | null>(null)
const [oauthError, setOauthError] = useState<string | null>(null) const [oauthError, setOauthError] = useState<string | null>(null)
const [tab, setTab] = useState(0) const [tab, setTab] = useState(0)
@@ -40,7 +52,7 @@ export function AuthPage() {
setSearchParams({}, { replace: true }) setSearchParams({}, { replace: true })
}, 0) }, 0)
return () => clearTimeout(timeoutId) return () => clearTimeout(timeoutId)
}, []) }, [searchParams, setSearchParams])
if (showForgot) { if (showForgot) {
return ( return (