api ulandi
This commit is contained in:
@@ -20,9 +20,19 @@ const NEWS_CATEGORY = "dashboard/dashboard-category/";
|
||||
const HOTEL = "dashboard/dashboard-hotel/";
|
||||
const FAQ = "dashboard/dashboard-faq/";
|
||||
const FAQ_CATEGORIES = "dashboard/dashboard-faq-category/";
|
||||
const SITE_SEO = "dashboard/dashboard-site-seo/";
|
||||
const OFFERTA = "dashboard/dashboard-site-offerta/";
|
||||
const HELP_PAGE = "dashboard/dashboard-site-help-page/";
|
||||
const SITE_SETTING = "dashboard/dashboard-site-settings/";
|
||||
const SUPPORT_USER = "dashboard/dashboard-support/";
|
||||
const SUPPORT_AGENCY = "dashboard/dashboard-travel-agency-request/";
|
||||
const USER_ORDERS = "dashboard/dashboard-ticket-order/";
|
||||
const POPULAR_TOURS = "dashboard/dashboard-ticket-featured/";
|
||||
const BANNER = "dashboard/dashboard-site-banner/";
|
||||
|
||||
export {
|
||||
AUTH_LOGIN,
|
||||
BANNER,
|
||||
BASE_URL,
|
||||
DOWNLOAD_PDF,
|
||||
FAQ,
|
||||
@@ -32,6 +42,7 @@ export {
|
||||
GET_ALL_USERS,
|
||||
GET_ME,
|
||||
GET_TICKET,
|
||||
HELP_PAGE,
|
||||
HOTEL,
|
||||
HOTEL_BADGE,
|
||||
HOTEL_FEATURES,
|
||||
@@ -40,6 +51,13 @@ export {
|
||||
HPTEL_TYPES,
|
||||
NEWS,
|
||||
NEWS_CATEGORY,
|
||||
OFFERTA,
|
||||
POPULAR_TOURS,
|
||||
SITE_SEO,
|
||||
SITE_SETTING,
|
||||
SUPPORT_AGENCY,
|
||||
SUPPORT_USER,
|
||||
TOUR_TRANSPORT,
|
||||
UPDATE_USER,
|
||||
USER_ORDERS,
|
||||
};
|
||||
|
||||
@@ -328,5 +328,143 @@
|
||||
"Breakfast Only": "Только завтрак",
|
||||
"Half Board": "Полупансион (завтрак и обед или ужин)",
|
||||
"Full Board": "Полный пансион (завтрак, обед и ужин)",
|
||||
"All Inclusive": "Всё включено (питание, напитки и услуги полностью)"
|
||||
"All Inclusive": "Всё включено (питание, напитки и услуги полностью)",
|
||||
"(1 kishi uchun)": "(на 1 человека)",
|
||||
"hamrohlar soni (eng kamida)": "количество компаньонов (минимум)",
|
||||
"hamrohlar soni (eng ko'pida)": "количество компаньонов (максимальное)",
|
||||
"Yo'lovchilar soni": "Количество пассажиров",
|
||||
"Tarifni tanlang": "Выберите тариф",
|
||||
"Mavjud tariflar": "Доступные тарифы",
|
||||
"Transport tanlang": "Выбрать транспорт",
|
||||
"Mavjud transportlar": "Доступные транспортные средства",
|
||||
"Visa talab qilinadimi": "Требуется ли виза",
|
||||
"Ha": "Да",
|
||||
"Yo'q": "Нет",
|
||||
"Banner": "Баннер",
|
||||
"Faqat bitta rasm yuklash mumkin": "Можно загрузить только одно изображение",
|
||||
"Qo'shimcha rasmlar": "Дополнительные изображения",
|
||||
"Qulaylik nomi (ru)": "Название удобства (ru)",
|
||||
"Yangi xizmat qo'shish": "Добавить новую услугу",
|
||||
"Taom nomi": "Название блюда",
|
||||
"Taom tavsifi": "Описание блюда",
|
||||
"Yo'nalishlar": "Направления",
|
||||
"Yo'nalish qo'shish": "Добавить маршрут",
|
||||
"Davomiylik (kun)": "Продолжительность (дни)",
|
||||
"Bu bo'limda savollar yo'q": "В этом разделе нет вопросов",
|
||||
"Yangi FAQ qo'shish": "Добавить новый FAQ",
|
||||
"Pending Payment": "Ожидается оплата",
|
||||
"Pending Confirmation": "Ожидается подтверждение",
|
||||
"Confirmed": "Подтверждено",
|
||||
"Completed": "Выполнено",
|
||||
"pending": "В ожидании",
|
||||
"done": "Выполнено",
|
||||
"failed": "Неудачно",
|
||||
"Yordam so'rovlari": "Запросы помощи",
|
||||
"Batafsil ko'rish": "Подробнее",
|
||||
"Agentlikka tegishli": "Принадлежащий агентству",
|
||||
"Yopish": "Закрыть",
|
||||
"Yakunlandi deb belgilash": "Отметить как завершенное",
|
||||
"Kutilmoqda deb belgilash": "Отметить как ожидаемое",
|
||||
"Natija topilmadi": "Результат не найден",
|
||||
"Barchasi": "Все",
|
||||
"Sayt bo'yicha": "На сайте",
|
||||
"Diqqat! O'chirish": "Внимание! Удалить",
|
||||
"Siz rostdan ham ushbu so'rovni o'chirmoqchimisiz?": "Вы уверены, что хотите удалить этот запрос?",
|
||||
"O'chirishda xatolik yuz berdi": "Ошибка при удалении",
|
||||
"Muvaffaqiyatli o'chirildi": "Удалено успешно",
|
||||
"Agentlik so'rovlari": "Агентские запросы",
|
||||
"Qidiruv (ism, email yoki telefon)...": "Поиск (имя, email или телефон)...",
|
||||
"Tozalash": "Очистка",
|
||||
"So'rov topilmadi": "Запрос не найден",
|
||||
"Tafsilotlar": "Подробности",
|
||||
"Javob yozish": "Написать ответ",
|
||||
"Hujjatlar": "Документы",
|
||||
"Hujjat": "Документ",
|
||||
"Hujjat topilmadi": "Документ не найден",
|
||||
"Qabul qilish": "Принять",
|
||||
"Rad etish": "Отказ",
|
||||
"Popular": "Популярный",
|
||||
"SEO Manager": "SEO Менеджер",
|
||||
"Saytingizni qidiruv tizimida yaxshi pozitsiyaga keltiring": "Продвиньте свой сайт в поисковых системах",
|
||||
"Page Title": "Заголовок страницы",
|
||||
"Sahifa sarlavhasi (30–60 belgi)": "Заголовок страницы (30–60 символов)",
|
||||
"Meta Description": "Мета описание",
|
||||
"Sahifa tavsifi (120–160 belgi)": "Описание страницы (120–160 символов)",
|
||||
"Keywords": "Ключевые слова",
|
||||
"Kalit so'zlar (vergul bilan ajratilgan)": "Ключевые слова (через запятую)",
|
||||
"Masalan: Python, Web Development, Coding": "Например: Python, Web Development, Coding",
|
||||
"Open Graph (Ijtimoiy Tarmoqlar)": "Open Graph (Социальные сети)",
|
||||
"OG Title": "OG Заголовок",
|
||||
"Ijtimoiy tarmoqdagi sarlavha": "Заголовок в социальных сетях",
|
||||
"OG Description": "OG Описание",
|
||||
"Ijtimoiy tarmoqdagi tavsif": "Описание в социальных сетях",
|
||||
"OG Image": "OG Изображение",
|
||||
"Saqlangan SEO Ma’lumotlari": "Сохранённые SEO данные",
|
||||
"Hozircha SEO ma’lumotlari mavjud emas.": "Пока нет данных по SEO.",
|
||||
"Ma’lumotlar muvaffaqiyatli saqlandi": "Данные успешно сохранены",
|
||||
"Muvaffaqiyatli yaratildi": "Успешно создано",
|
||||
"Muvaffaqiyatli yangilandi": "Успешно обновлено",
|
||||
"Sarlavha kiritish majburiy": "Необходимо ввести заголовок",
|
||||
"Sarlavha kamida 3 ta belgidan iborat bo'lishi kerak": "Заголовок должен содержать не менее 3 символов",
|
||||
"Kontent kiritish majburiy": "Необходимо ввести содержимое",
|
||||
"Kontent kamida 10 ta belgidan iborat bo'lishi kerak": "Содержимое должно содержать не менее 10 символов",
|
||||
"Kimlar uchun degan maydonni tanlang": "Выберите поле «Для кого»",
|
||||
"Iltimos, barcha majburiy maydonlarni to'ldiring": "Пожалуйста, заполните все обязательные поля",
|
||||
"Ommaviy oferta": "Публичная оферта",
|
||||
"Yangi oferta yaratish": "Создать новую оферту",
|
||||
"Ommaviy oferta sarlavhasi": "Заголовок публичной оферты",
|
||||
"Kontent": "Содержимое",
|
||||
"Oferta matnini kiriting...": "Введите текст оферты...",
|
||||
"Kimlar uchun": "Для кого",
|
||||
"Barcha": "Все",
|
||||
"Jismoniy shaxslar uchun": "Для физических лиц",
|
||||
"Yuridik shaxslar uchun": "Для юридических лиц",
|
||||
"O'chirish tasdiqlash": "Подтверждение удаления",
|
||||
"Haqiqatan ham bu ofertani o'chirmoqchimisiz? Bu amalni bekor qilib bo'lmaydi.": "Вы действительно хотите удалить эту оферту? Это действие нельзя отменить.",
|
||||
"Yordam sahifalari boshqaruvi": "Управление страницами помощи",
|
||||
"Yangi yordam sahifasi yaratish": "Создать новую страницу помощи",
|
||||
"Yordam sahifasi sarlavhasi": "Заголовок страницы помощи",
|
||||
"Yordam matnini kiriting...": "Введите текст помощи...",
|
||||
"Sahifa turi": "Тип страницы",
|
||||
"Sahifa turini tanlang": "Выберите тип страницы",
|
||||
"Qo‘llanma": "Инструкция",
|
||||
"Maxfiylik siyosati": "Политика конфиденциальности",
|
||||
"Faol emas": "Неактивно",
|
||||
"Yaratish": "Создать",
|
||||
"Natija topilmadi.": "Результаты не найдены.",
|
||||
"O‘chirishni tasdiqlash": "Подтверждение удаления",
|
||||
"Haqiqatan ham bu yordam sahifasini o‘chirmoqchimisiz? Bu amalni bekor qilib bo‘lmaydi.": "Вы действительно хотите удалить эту страницу помощи? Это действие нельзя отменить.",
|
||||
"Contact settings": "Настройки контактов",
|
||||
"Hozircha kontakt ma'lumotlari qo'shilmagan": "Пока нет контактных данных",
|
||||
"Sayt uchun telegram, instagram, manzil, email va telefonni bu yerda saqlang. Siz faqat bir marta qo'sha olasiz — keyin tahrirlash mumkin.": "Сохраните свои Telegram, Instagram, адрес, адрес электронной почты и телефон для сайта здесь. Вы можете добавить только один раз - затем вы можете редактировать.",
|
||||
"Kontakt ma'lumotlari": "Контактная информация",
|
||||
"Kontaktni tahrirlash": "Редактировать контакт",
|
||||
"Kontakt qo'shish": "Добавить контакт",
|
||||
"Asosiy telefon": "Основной телефон",
|
||||
"Qo'shimcha telefon": "Дополнительный телефон",
|
||||
"Muvaffaqiyatli saqlandi": "Успешно сохранено",
|
||||
"Mehmonxona reytingi": "Рейтинг отеля",
|
||||
"Taom rejasi": "План питания",
|
||||
"Tanlang": "Выберите",
|
||||
"Mehmonxona turlari": "Типы отелей",
|
||||
"Yana tanlang...": "Выберите ещё...",
|
||||
"Mehmonxona xususiyatlari": "Характеристики отеля",
|
||||
"Xususiyat turlari": "Типы свойств",
|
||||
"Sayt uchun Banner": "Баннер для сайта",
|
||||
"Sayt Bannerlari": "Баннеры сайта",
|
||||
"Bannerlarni boshqarish": "Управление баннерами",
|
||||
"Rasm": "Изображение",
|
||||
"Tavsif": "Описание",
|
||||
"Joylashuvi": "Расположение",
|
||||
"Hozircha bannerlar mavjud emas": "Пока нет баннеров",
|
||||
"Bannerni tahrirlash": "Редактировать баннер",
|
||||
"Yangi banner qo'shish": "Добавить новый баннер",
|
||||
"Havola URL": "URL адрес",
|
||||
"Asosiy": "Основная",
|
||||
"Kun taklifi": "Приглашение дня",
|
||||
"Mashhur yo‘nalishlar": "Известные направления",
|
||||
"Reytingi baland turlar": "Высокорейтинговые туры",
|
||||
"Status muvaffaqiyatli yangilandi": "Статус успешно обновлён",
|
||||
"Statusni yangilashda xatolik yuz berdi": "Ошибка обновления статуса",
|
||||
"Refunded": "Подтверждено"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
"FAQ Kategoriyalar": "FAQ Kategoriyalar",
|
||||
"Foydalanuvchini o'chirish": "Foydalanuvchini o'chirish",
|
||||
"Siz": "Siz",
|
||||
"(1 kishi uchun)": "(1 kishi uchun)",
|
||||
"hamrohlar soni (eng kamida)": "hamrohlar soni (eng kamida)",
|
||||
"foydalanuvchini o'chirmoqchimisiz?": "foydalanuvchini o'chirmoqchimisiz?",
|
||||
"Ushbu amalni qaytarib bo'lmaydi": "Ushbu amalni qaytarib bo'lmaydi.",
|
||||
"Bekor qilish": "Bekor qilish",
|
||||
@@ -303,6 +305,8 @@
|
||||
"Yangiliklar soni": "Yangiliklar soni",
|
||||
"Harakatlar": "Harakatlar",
|
||||
"Hech qanday kategoriya topilmadi": "Hech qanday kategoriya topilmadi",
|
||||
"Natija topilmadi": "Natija topilmadi",
|
||||
"Yangi kategoriya": "Yangi kategoriya",
|
||||
"Kategoriya tahrirlash": "Kategoriya tahrirlash",
|
||||
"Yangi kategoriya qo‘shish": "Yangi kategoriya qo‘shish",
|
||||
"FAQ (Savol va javoblar)": "FAQ (Savol va javoblar)",
|
||||
@@ -328,5 +332,140 @@
|
||||
"Breakfast Only": "Faqat nonushta",
|
||||
"Half Board": "Yarim pansion (nonushta va tushlik yoki kechki ovqat)",
|
||||
"Full Board": "To‘liq pansion (nonushta, tushlik va kechki ovqat)",
|
||||
"All Inclusive": "To‘liq pansion (nonushta, tushlik va kechki ovqat)"
|
||||
"All Inclusive": "To‘liq pansion (nonushta, tushlik va kechki ovqat)",
|
||||
"hamrohlar soni (eng ko'pida)": "hamrohlar soni (eng ko'pida)",
|
||||
"Yo'lovchilar soni": "Yo'lovchilar soni",
|
||||
"Tarifni tanlang": "Tarifni tanlang",
|
||||
"Mavjud tariflar": "Mavjud tariflar",
|
||||
"Transport tanlang": "Transport tanlang",
|
||||
"Mavjud transportlar": "Mavjud transportlar",
|
||||
"Visa talab qilinadimi": "Visa talab qilinadimi",
|
||||
"Ha": "Ha",
|
||||
"Yo'q": "Yo'q",
|
||||
"Banner": "Banner",
|
||||
"Faqat bitta rasm yuklash mumkin": "Faqat bitta rasm yuklash mumkin",
|
||||
"Qo'shimcha rasmlar": "Qo'shimcha rasmlar",
|
||||
"Qulaylik nomi (ru)": "Qulaylik nomi (ru)",
|
||||
"Yangi xizmat qo'shish": "Yangi xizmat qo'shish",
|
||||
"Taom nomi": "Taom nomi",
|
||||
"Taom tavsifi": "Taom tavsifi",
|
||||
"Yo'nalishlar": "Yo'nalishlar",
|
||||
"Yo'nalish qo'shish": "Yo'nalish qo'shish",
|
||||
"Davomiylik (kun)": "Davomiylik (kun)",
|
||||
"Bu bo'limda savollar yo'q": "Bu bo'limda savollar yo'q",
|
||||
"Yangi FAQ qo'shish": "Yangi FAQ qo'shish",
|
||||
"Pending Payment": "To‘lov kutilmoqda",
|
||||
"Pending Confirmation": "Tasdiqlash kutilmoqda",
|
||||
"Confirmed": "Tasdiqlangan",
|
||||
"Completed": "Bajarilgan",
|
||||
"pending": "Kutilmoqda",
|
||||
"done": "Yakunlangan",
|
||||
"failed": "Muvaffaqiyatsiz",
|
||||
"Yordam so'rovlari": "Yordam so'rovlari",
|
||||
"Batafsil ko'rish": "Batafsil ko'rish",
|
||||
"Agentlikka tegishli": "Agentlikka tegishli",
|
||||
"Yopish": "Yopish",
|
||||
"Yakunlandi deb belgilash": "Yakunlandi deb belgilash",
|
||||
"Kutilmoqda deb belgilash": "Kutilmoqda deb belgilash",
|
||||
"Barchasi": "Barchasi",
|
||||
"Sayt bo'yicha": "Sayt bo'yicha",
|
||||
"Diqqat! O'chirish": "Diqqat! O'chirish",
|
||||
"Siz rostdan ham ushbu so'rovni o'chirmoqchimisiz?": "Siz rostdan ham ushbu so'rovni o'chirmoqchimisiz?",
|
||||
"O'chirishda xatolik yuz berdi": "O'chirishda xatolik yuz berdi",
|
||||
"Muvaffaqiyatli o'chirildi": "Muvaffaqiyatli o'chirildi",
|
||||
"Agentlik so'rovlari": "Agentlik so'rovlari",
|
||||
"Qidiruv (ism, email yoki telefon)...": "Qidiruv (ism, email yoki telefon)...",
|
||||
"Tozalash": "Tozalash",
|
||||
"So'rov topilmadi": "So'rov topilmadi",
|
||||
"Tafsilotlar": "Tafsilotlar",
|
||||
"Javob yozish": "Javob yozish",
|
||||
"Hujjatlar": "Hujjatlar",
|
||||
"Hujjat": "Hujjat",
|
||||
"Hujjat topilmadi": "Hujjat topilmadi",
|
||||
"Qabul qilish": "Qabul qilish",
|
||||
"Rad etish": "Rad etish",
|
||||
"Popular": "Mashhur",
|
||||
"SEO Manager": "SEO Menejer",
|
||||
"Saytingizni qidiruv tizimida yaxshi pozitsiyaga keltiring": "Saytingizni qidiruv tizimida yaxshi pozitsiyaga keltiring",
|
||||
"Page Title": "Sahifa sarlavhasi",
|
||||
"Sahifa sarlavhasi (30–60 belgi)": "Sahifa sarlavhasi (30–60 belgi)",
|
||||
"Meta Description": "Meta tavsif",
|
||||
"Sahifa tavsifi (120–160 belgi)": "Sahifa tavsifi (120–160 belgi)",
|
||||
"Keywords": "Kalit so‘zlar",
|
||||
"Kalit so'zlar (vergul bilan ajratilgan)": "Kalit so‘zlar (vergul bilan ajratilgan)",
|
||||
"Masalan: Python, Web Development, Coding": "Masalan: Python, Web Development, Coding",
|
||||
"Open Graph (Ijtimoiy Tarmoqlar)": "Open Graph (Ijtimoiy tarmoqlar)",
|
||||
"OG Title": "OG Sarlavha",
|
||||
"Ijtimoiy tarmoqdagi sarlavha": "Ijtimoiy tarmoqdagi sarlavha",
|
||||
"OG Description": "OG Tavsif",
|
||||
"Ijtimoiy tarmoqdagi tavsif": "Ijtimoiy tarmoqdagi tavsif",
|
||||
"OG Image": "OG Rasm",
|
||||
"Saqlangan SEO Ma’lumotlari": "Saqlangan SEO ma’lumotlari",
|
||||
"Hozircha SEO ma’lumotlari mavjud emas.": "Hozircha SEO ma’lumotlari mavjud emas.",
|
||||
"Ma’lumotlar muvaffaqiyatli saqlandi": "Ma’lumotlar muvaffaqiyatli saqlandi",
|
||||
"Muvaffaqiyatli yaratildi": "Muvaffaqiyatli yaratildi",
|
||||
"Muvaffaqiyatli yangilandi": "Muvaffaqiyatli yangilandi",
|
||||
"Sarlavha kiritish majburiy": "Sarlavha kiritish majburiy",
|
||||
"Sarlavha kamida 3 ta belgidan iborat bo'lishi kerak": "Sarlavha kamida 3 ta belgidan iborat bo'lishi kerak",
|
||||
"Kontent kiritish majburiy": "Kontent kiritish majburiy",
|
||||
"Kontent kamida 10 ta belgidan iborat bo'lishi kerak": "Kontent kamida 10 ta belgidan iborat bo'lishi kerak",
|
||||
"Kimlar uchun degan maydonni tanlang": "Kimlar uchun degan maydonni tanlang",
|
||||
"Iltimos, barcha majburiy maydonlarni to'ldiring": "Iltimos, barcha majburiy maydonlarni to'ldiring",
|
||||
"Ommaviy oferta": "Ommaviy oferta",
|
||||
"Yangi oferta yaratish": "Yangi oferta yaratish",
|
||||
"Ommaviy oferta sarlavhasi": "Ommaviy oferta sarlavhasi",
|
||||
"Kontent": "Kontent",
|
||||
"Oferta matnini kiriting...": "Oferta matnini kiriting...",
|
||||
"Kimlar uchun": "Kimlar uchun",
|
||||
"Barcha": "Barcha",
|
||||
"Jismoniy shaxslar uchun": "Jismoniy shaxslar uchun",
|
||||
"Yuridik shaxslar uchun": "Yuridik shaxslar uchun",
|
||||
"O'chirish tasdiqlash": "O'chirish tasdiqlash",
|
||||
"Haqiqatan ham bu ofertani o'chirmoqchimisiz? Bu amalni bekor qilib bo'lmaydi.": "Haqiqatan ham bu ofertani o'chirmoqchimisiz? Bu amalni bekor qilib bo'lmaydi.",
|
||||
"Yordam sahifalari boshqaruvi": "Yordam sahifalari boshqaruvi",
|
||||
"Yangi yordam sahifasi yaratish": "Yangi yordam sahifasi yaratish",
|
||||
"Yordam sahifasi sarlavhasi": "Yordam sahifasi sarlavhasi",
|
||||
"Yordam matnini kiriting...": "Yordam matnini kiriting...",
|
||||
"Sahifa turi": "Sahifa turi",
|
||||
"Sahifa turini tanlang": "Sahifa turini tanlang",
|
||||
"Qo‘llanma": "Qo‘llanma",
|
||||
"Maxfiylik siyosati": "Maxfiylik siyosati",
|
||||
"Faol emas": "Faol emas",
|
||||
"Yaratish": "Yaratish",
|
||||
"Natija topilmadi.": "Natija topilmadi.",
|
||||
"O‘chirishni tasdiqlash": "O‘chirishni tasdiqlash",
|
||||
"Haqiqatan ham bu yordam sahifasini o‘chirmoqchimisiz? Bu amalni bekor qilib bo‘lmaydi.": "Haqiqatan ham bu yordam sahifasini o‘chirmoqchimisiz? Bu amalni bekor qilib bo‘lmaydi.",
|
||||
"Contact settings": "Kontakt sozlamalari",
|
||||
"Hozircha kontakt ma'lumotlari qo'shilmagan": "Hozircha kontakt ma'lumotlari qo'shilmagan",
|
||||
"Sayt uchun telegram, instagram, manzil, email va telefonni bu yerda saqlang. Siz faqat bir marta qo'sha olasiz — keyin tahrirlash mumkin.": "Sayt uchun telegram, instagram, manzil, email va telefonni bu yerda saqlang. Siz faqat bir marta qo'sha olasiz — keyin tahrirlash mumkin.",
|
||||
"Kontakt ma'lumotlari": "Kontakt ma'lumotlari",
|
||||
"Kontaktni tahrirlash": "Kontaktni tahrirlash",
|
||||
"Kontakt qo'shish": "Kontakt qo'shish",
|
||||
"Asosiy telefon": "Asosiy telefon",
|
||||
"Qo'shimcha telefon": "Qo'shimcha telefon",
|
||||
"Muvaffaqiyatli saqlandi": "Muvaffaqiyatli saqlandi",
|
||||
"Mehmonxona reytingi": "Mehmonxona reytingi",
|
||||
"Taom rejasi": "Taom rejasi",
|
||||
"Tanlang": "Tanlang",
|
||||
"Mehmonxona turlari": "Mehmonxona turlari",
|
||||
"Yana tanlang...": "Yana tanlang...",
|
||||
"Mehmonxona xususiyatlari": "Mehmonxona xususiyatlari",
|
||||
"Xususiyat turlari": "Xususiyat turlari",
|
||||
"Sayt uchun Banner": "Sayt uchun Banner",
|
||||
"Sayt Bannerlari": "Sayt Bannerlari",
|
||||
"Bannerlarni boshqarish": "Bannerlarni boshqarish",
|
||||
"Rasm": "Rasm",
|
||||
"Tavsif": "Tavsif",
|
||||
"Joylashuvi": "Joylashuvi",
|
||||
"Hozircha bannerlar mavjud emas": "Hozircha bannerlar mavjud emas",
|
||||
"Bannerni tahrirlash": "Bannerni tahrirlash",
|
||||
"Yangi banner qo'shish": "Yangi banner qo'shish",
|
||||
"Havola URL": "Havola URL",
|
||||
"Asosiy": "Asosiy",
|
||||
"Kun taklifi": "Kun taklifi",
|
||||
"Mashhur yo‘nalishlar": "Mashhur yo‘nalishlar",
|
||||
"Reytingi baland turlar": "Reytingi baland turlar",
|
||||
"Status muvaffaqiyatli yangilandi": "Status muvaffaqiyatli yangilandi",
|
||||
"Statusni yangilashda xatolik yuz berdi": "Statusni yangilashda xatolik yuz berdi",
|
||||
"Refunded": "Tasdiqlangan"
|
||||
}
|
||||
|
||||
239
src/shared/ui/carousel.tsx
Normal file
239
src/shared/ui/carousel.tsx
Normal file
@@ -0,0 +1,239 @@
|
||||
import * as React from "react"
|
||||
import useEmblaCarousel, {
|
||||
type UseEmblaCarouselType,
|
||||
} from "embla-carousel-react"
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||
|
||||
import { cn } from "@/shared/lib/utils"
|
||||
import { Button } from "@/shared/ui/button"
|
||||
|
||||
type CarouselApi = UseEmblaCarouselType[1]
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||
type CarouselOptions = UseCarouselParameters[0]
|
||||
type CarouselPlugin = UseCarouselParameters[1]
|
||||
|
||||
type CarouselProps = {
|
||||
opts?: CarouselOptions
|
||||
plugins?: CarouselPlugin
|
||||
orientation?: "horizontal" | "vertical"
|
||||
setApi?: (api: CarouselApi) => void
|
||||
}
|
||||
|
||||
type CarouselContextProps = {
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||
scrollPrev: () => void
|
||||
scrollNext: () => void
|
||||
canScrollPrev: boolean
|
||||
canScrollNext: boolean
|
||||
} & CarouselProps
|
||||
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||
|
||||
function useCarousel() {
|
||||
const context = React.useContext(CarouselContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useCarousel must be used within a <Carousel />")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
function Carousel({
|
||||
orientation = "horizontal",
|
||||
opts,
|
||||
setApi,
|
||||
plugins,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & CarouselProps) {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
},
|
||||
plugins
|
||||
)
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||
|
||||
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||
if (!api) return
|
||||
setCanScrollPrev(api.canScrollPrev())
|
||||
setCanScrollNext(api.canScrollNext())
|
||||
}, [])
|
||||
|
||||
const scrollPrev = React.useCallback(() => {
|
||||
api?.scrollPrev()
|
||||
}, [api])
|
||||
|
||||
const scrollNext = React.useCallback(() => {
|
||||
api?.scrollNext()
|
||||
}, [api])
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault()
|
||||
scrollPrev()
|
||||
} else if (event.key === "ArrowRight") {
|
||||
event.preventDefault()
|
||||
scrollNext()
|
||||
}
|
||||
},
|
||||
[scrollPrev, scrollNext]
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api || !setApi) return
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api) return
|
||||
onSelect(api)
|
||||
api.on("reInit", onSelect)
|
||||
api.on("select", onSelect)
|
||||
|
||||
return () => {
|
||||
api?.off("select", onSelect)
|
||||
}
|
||||
}, [api, onSelect])
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider
|
||||
value={{
|
||||
carouselRef,
|
||||
api: api,
|
||||
opts,
|
||||
orientation:
|
||||
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
canScrollPrev,
|
||||
canScrollNext,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onKeyDownCapture={handleKeyDown}
|
||||
className={cn("relative", className)}
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
data-slot="carousel"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
const { carouselRef, orientation } = useCarousel()
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={carouselRef}
|
||||
className="overflow-hidden"
|
||||
data-slot="carousel-content"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex",
|
||||
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
|
||||
const { orientation } = useCarousel()
|
||||
|
||||
return (
|
||||
<div
|
||||
role="group"
|
||||
aria-roledescription="slide"
|
||||
data-slot="carousel-item"
|
||||
className={cn(
|
||||
"min-w-0 shrink-0 grow-0 basis-full",
|
||||
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselPrevious({
|
||||
className,
|
||||
variant = "outline",
|
||||
size = "icon",
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||
|
||||
return (
|
||||
<Button
|
||||
data-slot="carousel-previous"
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute size-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "top-1/2 -left-12 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
)}
|
||||
disabled={!canScrollPrev}
|
||||
onClick={scrollPrev}
|
||||
{...props}
|
||||
>
|
||||
<ArrowLeft />
|
||||
<span className="sr-only">Previous slide</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselNext({
|
||||
className,
|
||||
variant = "outline",
|
||||
size = "icon",
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||
|
||||
return (
|
||||
<Button
|
||||
data-slot="carousel-next"
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute size-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "top-1/2 -right-12 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
)}
|
||||
disabled={!canScrollNext}
|
||||
onClick={scrollNext}
|
||||
{...props}
|
||||
>
|
||||
<ArrowRight />
|
||||
<span className="sr-only">Next slide</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
type CarouselApi,
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselPrevious,
|
||||
CarouselNext,
|
||||
}
|
||||
104
src/shared/ui/infiniteScrollSelect.tsx
Normal file
104
src/shared/ui/infiniteScrollSelect.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/shared/ui/select";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface InfiniteScrollSelectProps<T> {
|
||||
value: string;
|
||||
onValueChange: (value: string) => void;
|
||||
placeholder: string;
|
||||
label: string;
|
||||
data: T[];
|
||||
hasNextPage?: boolean;
|
||||
isFetchingNextPage?: boolean;
|
||||
fetchNextPage: () => void;
|
||||
renderOption: (item: T) => {
|
||||
key: string | number;
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
isLoading?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InfiniteScrollSelect<T>({
|
||||
value,
|
||||
onValueChange,
|
||||
placeholder,
|
||||
label,
|
||||
data,
|
||||
hasNextPage,
|
||||
isFetchingNextPage,
|
||||
fetchNextPage,
|
||||
renderOption,
|
||||
isLoading = false,
|
||||
className = "",
|
||||
}: InfiniteScrollSelectProps<T>) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
||||
// Scroll oxiriga 50px qolganda keyingi page ni yuklash
|
||||
if (
|
||||
scrollHeight - scrollTop - clientHeight < 50 &&
|
||||
hasNextPage &&
|
||||
!isFetchingNextPage
|
||||
) {
|
||||
fetchNextPage();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Select onValueChange={onValueChange} value={value} disabled={isLoading}>
|
||||
<SelectTrigger
|
||||
className={`w-full !h-12 bg-gray-800 border-gray-700 text-white ${className}`}
|
||||
>
|
||||
<SelectValue placeholder={placeholder} />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-gray-800 border-gray-700 text-white max-h-[200px] overflow-hidden">
|
||||
<SelectGroup>
|
||||
<SelectLabel>{label}</SelectLabel>
|
||||
<div
|
||||
data-radix-select-viewport
|
||||
className="overflow-y-auto max-h-[180px]"
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{data && data?.length === 0 && !isLoading && (
|
||||
<div className="text-center py-4 text-gray-400 text-sm">
|
||||
{t("Ma'lumot topilmadi")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data.map((item) => {
|
||||
const option = renderOption(item);
|
||||
return (
|
||||
<SelectItem key={option.key} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
|
||||
{isFetchingNextPage && (
|
||||
<div className="text-center py-2 text-gray-400 text-sm">
|
||||
{t("Yuklanmoqda...")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!hasNextPage && data && data.length > 0 && (
|
||||
<div className="text-center py-2 text-gray-500 text-xs">
|
||||
{t("Barcha ma'lumotlar yuklandi")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
@@ -42,11 +42,13 @@ const LazyIcon: React.FC<{ name: string }> = ({ name }) => {
|
||||
|
||||
interface IconSelectProps {
|
||||
selectedIcon?: string;
|
||||
defaultIcon?: string;
|
||||
setSelectedIcon: (value: string) => void;
|
||||
}
|
||||
|
||||
const IconSelect: React.FC<IconSelectProps> = ({
|
||||
selectedIcon,
|
||||
defaultIcon = "HelpCircle",
|
||||
setSelectedIcon,
|
||||
}) => {
|
||||
const [icons, setIcons] = useState<string[]>([]);
|
||||
@@ -125,7 +127,10 @@ const IconSelect: React.FC<IconSelectProps> = ({
|
||||
{selectedIcon}
|
||||
</div>
|
||||
) : (
|
||||
t("Ikonka tanlang")
|
||||
<div className="flex items-center gap-2 text-gray-500">
|
||||
<LazyIcon name={defaultIcon} />
|
||||
{defaultIcon}
|
||||
</div>
|
||||
)}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
|
||||
29
src/shared/ui/switch.tsx
Normal file
29
src/shared/ui/switch.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitive from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/shared/lib/utils"
|
||||
|
||||
function Switch({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
|
||||
return (
|
||||
<SwitchPrimitive.Root
|
||||
data-slot="switch"
|
||||
className={cn(
|
||||
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<SwitchPrimitive.Thumb
|
||||
data-slot="switch-thumb"
|
||||
className={cn(
|
||||
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitive.Root>
|
||||
)
|
||||
}
|
||||
|
||||
export { Switch }
|
||||
Reference in New Issue
Block a user