Add a Statistics page for storefront visits and instruction 1:1/3:2 crops.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-01 11:10:52 +03:30
co-authored by Cursor
parent d9bdfbbb12
commit 6be867ea7a
11 changed files with 410 additions and 17 deletions
@@ -29,6 +29,13 @@ import { flattenCategories } from '../utils/categories'
import pageStyles from '../components/PageContent.module.css'
import styles from './AddNewProductPage.module.css'
type CoverImageAspectId = '1:1' | '3:2'
const COVER_IMAGE_ASPECTS: { id: CoverImageAspectId; aspect: number }[] = [
{ id: '1:1', aspect: 1 },
{ id: '3:2', aspect: 3 / 2 },
]
export function AddNewInstructionPage() {
const { id } = useParams()
const navigate = useNavigate()
@@ -45,6 +52,7 @@ export function AddNewInstructionPage() {
const [videoProvider, setInstructionProvider] = useState<VideoProvider>('youtube')
const [embedCode, setEmbedCode] = useState('')
const [coverImage, setCoverImage] = useState<string | null>(null)
const [coverImageAspect, setCoverImageAspect] = useState<CoverImageAspectId>('3:2')
const [tags, setTags] = useState<string[]>([])
const [featuredMediaId, setFeaturedMediaId] = useState<string | null>(null)
const [loaded, setLoaded] = useState(!isEdit)
@@ -52,6 +60,8 @@ export function AddNewInstructionPage() {
const [error, setError] = useState('')
const categoryOptions = flattenCategories(categories)
const selectedAspect =
COVER_IMAGE_ASPECTS.find((option) => option.id === coverImageAspect)?.aspect ?? 3 / 2
useEffect(() => {
const controller = new AbortController()
@@ -197,16 +207,44 @@ export function AddNewInstructionPage() {
<form className={styles.form} onSubmit={handleSubmit}>
<div className={styles.formGrid}>
<div className={`${styles.field} ${styles.col3} ${styles.rowSpan4}`}>
<div className={`${styles.field} ${styles.col3} ${styles.rowSpan4} ${styles.thumbnailField}`}>
<label>{t('instruction.form.coverImage')}</label>
<ImageCropper
value={coverImage}
onChange={setCoverImage}
aspect={3 / 2}
aspect={selectedAspect}
uploadLabel={t('instruction.form.uploadCoverImage')}
hint={t('instruction.form.cropHint')}
hint={t('instruction.form.cropHint', { ratio: coverImageAspect })}
changeLabel={t('instruction.form.changeCoverImage')}
/>
<div
className={styles.aspectSwitch}
role="radiogroup"
aria-label={t('instruction.form.aspectAria')}
>
{COVER_IMAGE_ASPECTS.map((option) => (
<button
key={option.id}
type="button"
role="radio"
aria-checked={coverImageAspect === option.id}
className={`${styles.aspectSwitchBtn} ${
coverImageAspect === option.id ? styles.aspectSwitchBtnSelected : ''
}`}
onClick={() => {
if (option.id === coverImageAspect) return
setCoverImageAspect(option.id)
if (coverImage) {
setCoverImage(null)
setFeaturedMediaId(null)
}
}}
disabled={isSubmitting}
>
{option.id}
</button>
))}
</div>
</div>
<div className={styles.formColumn}>