diff --git a/src/components/shared/NotificationModal.module.css b/src/components/shared/NotificationModal.module.css index ccce651..7c77dad 100644 --- a/src/components/shared/NotificationModal.module.css +++ b/src/components/shared/NotificationModal.module.css @@ -74,6 +74,10 @@ gap: var(--spacing-small); } +.spacer { + flex: 1; +} + .button { flex: 1; padding: var(--spacing-small); diff --git a/src/components/shared/ValidationModal.tsx b/src/components/shared/ValidationModal.tsx new file mode 100644 index 0000000..345b689 --- /dev/null +++ b/src/components/shared/ValidationModal.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import styles from './NotificationModal.module.css'; + +interface ValidationModalProps { + isVisible: boolean; + title: string; + message: string; + onContinue: () => void; +} + +const ValidationModal: React.FC = ({ + isVisible, + title, + message, + onContinue +}) => { + if (!isVisible) return null; + + return ( +
+
+
+
{title}
+
{message}
+
+ +
+
{/* Пустой элемент для выравнивания */} + +
+
+
+ ); +}; + +export default ValidationModal; diff --git a/src/screens/CreateStickerPack.module.css b/src/screens/CreateStickerPack.module.css index 65c005f..38d7d1d 100644 --- a/src/screens/CreateStickerPack.module.css +++ b/src/screens/CreateStickerPack.module.css @@ -5,6 +5,13 @@ padding: calc(3rem + var(--spacing-small)) var(--spacing-medium) var(--spacing-large); width: 100%; box-sizing: border-box; + position: relative; /* Добавляем для позиционирования фиксированной кнопки */ +} + +.content { + position: relative; + min-height: 100vh; /* Обеспечиваем, чтобы контент занимал как минимум всю высоту экрана */ + padding-bottom: calc(4rem + 80px + var(--safe-area-inset-bottom)); /* Отступ для кнопки */ } .header { @@ -132,19 +139,27 @@ } } -.actions { - display: flex; - justify-content: center; - margin-top: var(--spacing-medium); +/* Стили для контейнера кнопки */ +.createButtonContainer { + position: fixed; + bottom: calc(6rem + var(--safe-area-inset-bottom)); /* Увеличенный отступ от навигации */ + left: var(--spacing-medium); + right: var(--spacing-medium); + width: auto; + max-width: calc(28rem - 2 * var(--spacing-medium)); + margin: 0 auto; + z-index: 90; } .createButton { - padding: var(--spacing-small) var(--spacing-large); + width: 100%; + padding: calc(var(--spacing-small) * 1.5) var(--spacing-large); /* Увеличенный вертикальный padding для толщины */ background-color: var(--color-primary); color: white; border: none; border-radius: var(--border-radius); font-weight: 500; + font-size: 1.1rem; /* Увеличенный размер шрифта */ cursor: pointer; transition: transform 0.2s; } diff --git a/src/screens/CreateStickerPack.tsx b/src/screens/CreateStickerPack.tsx index 4d67c38..ffab32d 100644 --- a/src/screens/CreateStickerPack.tsx +++ b/src/screens/CreateStickerPack.tsx @@ -6,6 +6,7 @@ import apiService from '../services/api'; import { GeneratedImage } from '../types/api'; import { getCurrentUserId } from '../constants/user'; import EmojiPickerModal from '../components/shared/EmojiPickerModal'; +import ValidationModal from '../components/shared/ValidationModal'; /** * Транслитерирует кириллический текст в латиницу. @@ -61,6 +62,11 @@ const CreateStickerPack: React.FC = () => { const [isEmojiPickerVisible, setIsEmojiPickerVisible] = useState(false); const [activeEmojiIndex, setActiveEmojiIndex] = useState(null); + // Состояния для модального окна валидации + const [validationTitle, setValidationTitle] = useState(''); + const [validationMessage, setValidationMessage] = useState(''); + const [isValidationModalVisible, setIsValidationModalVisible] = useState(false); + // Функция для сворачивания клавиатуры const dismissKeyboard = () => { if (titleInputRef.current) { @@ -145,15 +151,24 @@ const CreateStickerPack: React.FC = () => { }); }; + // Обработчик закрытия модального окна валидации + const handleValidationModalClose = () => { + setIsValidationModalVisible(false); + }; + // Обработчик создания стикерпака const handleCreateStickerPack = async () => { if (!title.trim()) { - setError('Введите название стикерпака'); + setValidationTitle('Название не указано'); + setValidationMessage('Пожалуйста, введите название для вашего стикерпака.'); + setIsValidationModalVisible(true); return; } if (selectedImages.length === 0) { - setError('Выберите хотя бы одно изображение'); + setValidationTitle('Стикеры не выбраны'); + setValidationMessage('Пожалуйста, выберите хотя бы одно изображение для вашего стикерпака.'); + setIsValidationModalVisible(true); return; } @@ -190,7 +205,9 @@ const CreateStickerPack: React.FC = () => { navigate('/packs'); } catch (err) { console.error('Ошибка при создании стикерпака:', err); - setError('Не удалось создать стикерпак'); + setValidationTitle('Ошибка'); + setValidationMessage('Не удалось создать стикерпак. Пожалуйста, попробуйте еще раз.'); + setIsValidationModalVisible(true); } finally { setCreating(false); } @@ -208,82 +225,84 @@ const CreateStickerPack: React.FC = () => {

Создание стикерпака

-
-
- - setTitle(e.target.value)} - placeholder="Введите название стикерпака" - ref={titleInputRef} - onKeyDown={handleTitleKeyDown} - enterKeyHint="done" - /> -
+
+
+
+ + setTitle(e.target.value)} + placeholder="Введите название стикерпака" + ref={titleInputRef} + onKeyDown={handleTitleKeyDown} + enterKeyHint="done" + /> +
-
- - - {loading &&

Загрузка изображений...

} - - {!loading && availableImages.length === 0 && ( -

- У вас пока нет сгенерированных изображений. - Сначала создайте изображения в разделе "Создать стикер". -

- )} - - {!loading && availableImages.length > 0 && ( -
- {availableImages.map((image, index) => { - const isSelected = selectedImages.some(img => img.id === image.id); - const selectedIndex = selectedImages.findIndex(img => img.id === image.id); - - return ( -
handleImageSelect(image)} - > - {`Изображение - - {isSelected && ( -
- -
- )} -
- ); - })} -
- )} -
+
+ + + {loading &&

Загрузка изображений...

} + + {!loading && availableImages.length === 0 && ( +

+ У вас пока нет сгенерированных изображений. + Сначала создайте изображения в разделе "Создать стикер". +

+ )} + + {!loading && availableImages.length > 0 && ( +
+ {availableImages.map((image, index) => { + const isSelected = selectedImages.some(img => img.id === image.id); + const selectedIndex = selectedImages.findIndex(img => img.id === image.id); + + return ( +
handleImageSelect(image)} + > + {`Изображение + + {isSelected && ( +
+ +
+ )} +
+ ); + })} +
+ )} +
- {error &&

{error}

} - -
- + {error &&

{error}

}
+
+ +
+ {/* Модальное окно выбора эмодзи */} { onSelect={handleSelectEmoji} initialEmoji={activeEmojiIndex !== null ? (emojis[activeEmojiIndex] || '😊') : '😊'} /> + + {/* Модальное окно валидации */} +
); };