@promakeai/cli 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +212 -0
- package/dist/registry/about-page.json +45 -0
- package/dist/registry/about-section.json +40 -0
- package/dist/registry/animations.json +69 -0
- package/dist/registry/bento-grid-section.json +42 -0
- package/dist/registry/blog-core.json +74 -0
- package/dist/registry/blog-list-page.json +48 -0
- package/dist/registry/blog-section.json +43 -0
- package/dist/registry/cards-carousel-section.json +46 -0
- package/dist/registry/cart-drawer.json +43 -0
- package/dist/registry/cart-page.json +47 -0
- package/dist/registry/category-section.json +43 -0
- package/dist/registry/checkout-page.json +47 -0
- package/dist/registry/contact-info-grid.json +40 -0
- package/dist/registry/contact-page-centered.json +50 -0
- package/dist/registry/contact-page-map-overlay.json +54 -0
- package/dist/registry/contact-page-map-split.json +54 -0
- package/dist/registry/contact-page-split.json +49 -0
- package/dist/registry/contact-page.json +45 -0
- package/dist/registry/content-section.json +40 -0
- package/dist/registry/cookies-page.json +45 -0
- package/dist/registry/cta-section.json +40 -0
- package/dist/registry/docs/about-page.md +32 -0
- package/dist/registry/docs/about-section.md +33 -0
- package/dist/registry/docs/animations.md +44 -0
- package/dist/registry/docs/bento-grid-section.md +40 -0
- package/dist/registry/docs/blog-core.md +37 -0
- package/dist/registry/docs/blog-list-page.md +38 -0
- package/dist/registry/docs/blog-section.md +39 -0
- package/dist/registry/docs/cards-carousel-section.md +39 -0
- package/dist/registry/docs/cart-drawer.md +42 -0
- package/dist/registry/docs/cart-page.md +37 -0
- package/dist/registry/docs/category-section.md +34 -0
- package/dist/registry/docs/checkout-page.md +38 -0
- package/dist/registry/docs/contact-info-grid.md +33 -0
- package/dist/registry/docs/contact-page-centered.md +41 -0
- package/dist/registry/docs/contact-page-map-overlay.md +44 -0
- package/dist/registry/docs/contact-page-map-split.md +44 -0
- package/dist/registry/docs/contact-page-split.md +40 -0
- package/dist/registry/docs/contact-page.md +33 -0
- package/dist/registry/docs/content-section.md +35 -0
- package/dist/registry/docs/cookies-page.md +32 -0
- package/dist/registry/docs/cta-section.md +32 -0
- package/dist/registry/docs/ecommerce-core.md +41 -0
- package/dist/registry/docs/empty-page.md +31 -0
- package/dist/registry/docs/faq-categorized.md +38 -0
- package/dist/registry/docs/faq-simple.md +38 -0
- package/dist/registry/docs/favorites-blog-block.md +38 -0
- package/dist/registry/docs/favorites-ecommerce-block.md +38 -0
- package/dist/registry/docs/feature-section.md +33 -0
- package/dist/registry/docs/featured-products.md +38 -0
- package/dist/registry/docs/footer-detailed.md +33 -0
- package/dist/registry/docs/footer-minimal.md +32 -0
- package/dist/registry/docs/footer.md +32 -0
- package/dist/registry/docs/google-map.md +36 -0
- package/dist/registry/docs/header-centered-pill.md +37 -0
- package/dist/registry/docs/header-ecommerce.md +38 -0
- package/dist/registry/docs/header-mega.md +40 -0
- package/dist/registry/docs/header-minimal.md +38 -0
- package/dist/registry/docs/header-simple.md +32 -0
- package/dist/registry/docs/hero-cta.md +38 -0
- package/dist/registry/docs/hero-gradient.md +33 -0
- package/dist/registry/docs/hero-grid.md +40 -0
- package/dist/registry/docs/hero-profile.md +33 -0
- package/dist/registry/docs/hero.md +32 -0
- package/dist/registry/docs/login-page-split.md +40 -0
- package/dist/registry/docs/login-page.md +39 -0
- package/dist/registry/docs/newsletter-section.md +40 -0
- package/dist/registry/docs/order-card-compact.md +37 -0
- package/dist/registry/docs/order-detail-block.md +37 -0
- package/dist/registry/docs/orders-list-block.md +40 -0
- package/dist/registry/docs/payment-success-block.md +32 -0
- package/dist/registry/docs/post-card.md +37 -0
- package/dist/registry/docs/post-detail-block.md +37 -0
- package/dist/registry/docs/pricing-card.md +37 -0
- package/dist/registry/docs/pricing-section.md +39 -0
- package/dist/registry/docs/privacy-page.md +32 -0
- package/dist/registry/docs/product-card-detailed.md +42 -0
- package/dist/registry/docs/product-card-hover.md +35 -0
- package/dist/registry/docs/product-card.md +37 -0
- package/dist/registry/docs/product-detail-block.md +37 -0
- package/dist/registry/docs/product-detail-section.md +45 -0
- package/dist/registry/docs/products-page.md +39 -0
- package/dist/registry/docs/related-posts-block.md +38 -0
- package/dist/registry/docs/related-products-block.md +38 -0
- package/dist/registry/docs/service-card.md +34 -0
- package/dist/registry/docs/skill-card.md +33 -0
- package/dist/registry/docs/terms-page.md +32 -0
- package/dist/registry/docs/testimonials-carousel.md +40 -0
- package/dist/registry/docs/testimonials-grid.md +39 -0
- package/dist/registry/ecommerce-core.json +95 -0
- package/dist/registry/empty-page.json +45 -0
- package/dist/registry/faq-categorized.json +42 -0
- package/dist/registry/faq-simple.json +42 -0
- package/dist/registry/favorites-blog-block.json +43 -0
- package/dist/registry/favorites-ecommerce-block.json +43 -0
- package/dist/registry/feature-section.json +40 -0
- package/dist/registry/featured-products.json +43 -0
- package/dist/registry/footer-detailed.json +43 -0
- package/dist/registry/footer-minimal.json +40 -0
- package/dist/registry/footer.json +40 -0
- package/dist/registry/google-map.json +31 -0
- package/dist/registry/header-centered-pill.json +45 -0
- package/dist/registry/header-ecommerce.json +42 -0
- package/dist/registry/header-mega.json +47 -0
- package/dist/registry/header-minimal.json +45 -0
- package/dist/registry/header-simple.json +43 -0
- package/dist/registry/hero-cta.json +42 -0
- package/dist/registry/hero-gradient.json +40 -0
- package/dist/registry/hero-grid.json +42 -0
- package/dist/registry/hero-profile.json +62 -0
- package/dist/registry/hero.json +40 -0
- package/dist/registry/index.json +70 -0
- package/dist/registry/login-page-split.json +47 -0
- package/dist/registry/login-page.json +49 -0
- package/dist/registry/newsletter-section.json +44 -0
- package/dist/registry/order-card-compact.json +42 -0
- package/dist/registry/order-detail-block.json +42 -0
- package/dist/registry/orders-list-block.json +45 -0
- package/dist/registry/payment-success-block.json +40 -0
- package/dist/registry/post-card.json +42 -0
- package/dist/registry/post-detail-block.json +42 -0
- package/dist/registry/pricing-card.json +40 -0
- package/dist/registry/pricing-section.json +43 -0
- package/dist/registry/privacy-page.json +45 -0
- package/dist/registry/product-card-detailed.json +45 -0
- package/dist/registry/product-card-hover.json +40 -0
- package/dist/registry/product-card.json +42 -0
- package/dist/registry/product-detail-block.json +42 -0
- package/dist/registry/product-detail-section.json +46 -0
- package/dist/registry/products-page.json +48 -0
- package/dist/registry/related-posts-block.json +43 -0
- package/dist/registry/related-products-block.json +43 -0
- package/dist/registry/service-card.json +28 -0
- package/dist/registry/skill-card.json +28 -0
- package/dist/registry/terms-page.json +45 -0
- package/dist/registry/testimonials-carousel.json +44 -0
- package/dist/registry/testimonials-grid.json +43 -0
- package/package.json +52 -0
- package/template/.env +6 -0
- package/template/.prettierignore +3 -0
- package/template/.prettierrc +1 -0
- package/template/README.md +73 -0
- package/template/bun.lock +1007 -0
- package/template/components.json +22 -0
- package/template/eslint.config.js +32 -0
- package/template/index.html +285 -0
- package/template/package.json +92 -0
- package/template/promake.json +6 -0
- package/template/public/_redirects +1 -0
- package/template/public/data/database.db +0 -0
- package/template/public/favicon.svg +1 -0
- package/template/public/images/placeholder.png +0 -0
- package/template/public/robots.txt +14 -0
- package/template/scripts/init-db.ts +131 -0
- package/template/src/App.tsx +33 -0
- package/template/src/components/Footer.tsx +100 -0
- package/template/src/components/Header.tsx +79 -0
- package/template/src/components/Hero.tsx +69 -0
- package/template/src/components/LanguageSwitcher.tsx +47 -0
- package/template/src/components/Layout.tsx +25 -0
- package/template/src/components/Logo.tsx +64 -0
- package/template/src/components/ThemeSwitcher.tsx +58 -0
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +155 -0
- package/template/src/components/ui/alert.tsx +66 -0
- package/template/src/components/ui/aspect-ratio.tsx +11 -0
- package/template/src/components/ui/avatar.tsx +51 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/breadcrumb.tsx +109 -0
- package/template/src/components/ui/button-group.tsx +83 -0
- package/template/src/components/ui/button.tsx +62 -0
- package/template/src/components/ui/calendar.tsx +220 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/carousel.tsx +239 -0
- package/template/src/components/ui/chart.tsx +357 -0
- package/template/src/components/ui/checkbox.tsx +32 -0
- package/template/src/components/ui/collapsible.tsx +31 -0
- package/template/src/components/ui/command.tsx +182 -0
- package/template/src/components/ui/context-menu.tsx +252 -0
- package/template/src/components/ui/dialog.tsx +141 -0
- package/template/src/components/ui/drawer.tsx +135 -0
- package/template/src/components/ui/dropdown-menu.tsx +255 -0
- package/template/src/components/ui/empty.tsx +104 -0
- package/template/src/components/ui/field.tsx +246 -0
- package/template/src/components/ui/form.tsx +168 -0
- package/template/src/components/ui/hover-card.tsx +44 -0
- package/template/src/components/ui/input-group.tsx +170 -0
- package/template/src/components/ui/input-otp.tsx +75 -0
- package/template/src/components/ui/input.tsx +21 -0
- package/template/src/components/ui/item.tsx +193 -0
- package/template/src/components/ui/kbd.tsx +28 -0
- package/template/src/components/ui/label.tsx +24 -0
- package/template/src/components/ui/menubar.tsx +274 -0
- package/template/src/components/ui/navigation-menu.tsx +168 -0
- package/template/src/components/ui/pagination.tsx +127 -0
- package/template/src/components/ui/popover.tsx +48 -0
- package/template/src/components/ui/progress.tsx +29 -0
- package/template/src/components/ui/radio-group.tsx +45 -0
- package/template/src/components/ui/resizable.tsx +54 -0
- package/template/src/components/ui/scroll-area.tsx +58 -0
- package/template/src/components/ui/select.tsx +188 -0
- package/template/src/components/ui/separator.tsx +28 -0
- package/template/src/components/ui/sheet.tsx +137 -0
- package/template/src/components/ui/sidebar.tsx +726 -0
- package/template/src/components/ui/skeleton.tsx +13 -0
- package/template/src/components/ui/slider.tsx +63 -0
- package/template/src/components/ui/sonner.tsx +38 -0
- package/template/src/components/ui/spinner.tsx +16 -0
- package/template/src/components/ui/switch.tsx +31 -0
- package/template/src/components/ui/table.tsx +114 -0
- package/template/src/components/ui/tabs.tsx +66 -0
- package/template/src/components/ui/textarea.tsx +18 -0
- package/template/src/components/ui/toggle-group.tsx +81 -0
- package/template/src/components/ui/toggle.tsx +45 -0
- package/template/src/components/ui/tooltip.tsx +61 -0
- package/template/src/constants/constants.json +58 -0
- package/template/src/hooks/use-is-mobile.ts +21 -0
- package/template/src/hooks/use-page-title.ts +49 -0
- package/template/src/hooks/use-theme.ts +57 -0
- package/template/src/index.css +128 -0
- package/template/src/lang/en/about.json +4 -0
- package/template/src/lang/en/contact.json +39 -0
- package/template/src/lang/en/cookies.json +4 -0
- package/template/src/lang/en/footer.json +12 -0
- package/template/src/lang/en/forgotPassword.json +37 -0
- package/template/src/lang/en/header.json +10 -0
- package/template/src/lang/en/hero.json +8 -0
- package/template/src/lang/en/index.json +30 -0
- package/template/src/lang/en/login.json +18 -0
- package/template/src/lang/en/notfound.json +7 -0
- package/template/src/lang/en/privacy.json +4 -0
- package/template/src/lang/en/register.json +25 -0
- package/template/src/lang/en/terms.json +4 -0
- package/template/src/lang/index.ts +86 -0
- package/template/src/lang/tr/about.json +4 -0
- package/template/src/lang/tr/contact.json +39 -0
- package/template/src/lang/tr/cookies.json +4 -0
- package/template/src/lang/tr/footer.json +12 -0
- package/template/src/lang/tr/forgotPassword.json +37 -0
- package/template/src/lang/tr/header.json +10 -0
- package/template/src/lang/tr/hero.json +8 -0
- package/template/src/lang/tr/index.json +30 -0
- package/template/src/lang/tr/login.json +18 -0
- package/template/src/lang/tr/notfound.json +7 -0
- package/template/src/lang/tr/privacy.json +4 -0
- package/template/src/lang/tr/register.json +25 -0
- package/template/src/lang/tr/terms.json +4 -0
- package/template/src/lib/api.ts +237 -0
- package/template/src/lib/storage.ts +109 -0
- package/template/src/lib/utils.ts +15 -0
- package/template/src/main.tsx +13 -0
- package/template/src/modules/api/USAGE.md +515 -0
- package/template/src/modules/api/customer-client.ts +20 -0
- package/template/src/modules/api/get-error-message.ts +18 -0
- package/template/src/modules/api/validation/en.json +29 -0
- package/template/src/modules/api/validation/tr.json +29 -0
- package/template/src/modules/auth/USAGE.md +248 -0
- package/template/src/modules/auth/auth-header-menu.tsx +123 -0
- package/template/src/modules/auth/auth-store.ts +57 -0
- package/template/src/modules/auth/forgot-password-page.tsx +371 -0
- package/template/src/modules/auth/login-page.tsx +183 -0
- package/template/src/modules/auth/register-page.tsx +252 -0
- package/template/src/modules/auth/use-auth.ts +273 -0
- package/template/src/modules/db/adapters/IDataAdapter.ts +26 -0
- package/template/src/modules/db/adapters/SqliteAdapter.ts +364 -0
- package/template/src/modules/db/adapters/index.ts +2 -0
- package/template/src/modules/db/config.ts +59 -0
- package/template/src/modules/db/core/DataManager.ts +125 -0
- package/template/src/modules/db/core/types.ts +101 -0
- package/template/src/modules/db/index.ts +42 -0
- package/template/src/modules/db/react/QueryProvider.tsx +16 -0
- package/template/src/modules/db/react/index.ts +23 -0
- package/template/src/modules/db/react/queryClient.ts +64 -0
- package/template/src/modules/db/react/useRepository.ts +400 -0
- package/template/src/modules/db/utils/parsers.ts +96 -0
- package/template/src/pages/Index.tsx +108 -0
- package/template/src/pages/NotFound.tsx +35 -0
- package/template/src/router.tsx +14 -0
- package/template/src/types/index.ts +0 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.app.json +32 -0
- package/template/tsconfig.json +17 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +74 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "GiriÅŸ Yap",
|
|
3
|
+
"description": "Siparişlerinize, favorilerinize ve daha fazlasına erişmek için hesabınıza giriş yapın.",
|
|
4
|
+
"cardTitle": "GiriÅŸ",
|
|
5
|
+
"username": "Kullanıcı Adı",
|
|
6
|
+
"usernamePlaceholder": "Kullanıcı adınızı girin",
|
|
7
|
+
"password": "Åžifre",
|
|
8
|
+
"passwordPlaceholder": "Åžifrenizi girin",
|
|
9
|
+
"forgotPassword": "Åžifremi unuttum?",
|
|
10
|
+
"submit": "GiriÅŸ Yap",
|
|
11
|
+
"submitting": "Giriş yapılıyor...",
|
|
12
|
+
"noAccount": "Hesabınız yok mu?",
|
|
13
|
+
"registerLink": "Hesap oluÅŸturun",
|
|
14
|
+
"toastSuccessTitle": "Tekrar hoÅŸ geldiniz!",
|
|
15
|
+
"toastSuccessDesc": "Başarıyla giriş yaptınız.",
|
|
16
|
+
"toastErrorTitle": "Giriş başarısız",
|
|
17
|
+
"errorGeneric": "Giriş başarısız. Lütfen tekrar deneyin."
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pageNotFound": "Sayfa Bulunamadı",
|
|
3
|
+
"pageNotFoundDev": "Bu sayfayı henüz oluşturmadın",
|
|
4
|
+
"description": "Üzgünüz, aradığınız sayfa bulunamadı. Taşınmış veya mevcut olmayabilir.",
|
|
5
|
+
"descriptionDev": "Bu sayfayı oluşturmak için Promake'i kullanabilirsin.",
|
|
6
|
+
"goHome": "Ana Sayfaya Git"
|
|
7
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Hesap OluÅŸtur",
|
|
3
|
+
"description": "Bugün bize katılın ve özel avantajlardan, sipariş takibinden ve daha fazlasından yararlanın.",
|
|
4
|
+
"cardTitle": "Kayıt Ol",
|
|
5
|
+
"username": "Kullanıcı Adı",
|
|
6
|
+
"usernamePlaceholder": "Bir kullanıcı adı seçin",
|
|
7
|
+
"email": "E-posta",
|
|
8
|
+
"emailPlaceholder": "E-posta adresinizi girin",
|
|
9
|
+
"password": "Åžifre",
|
|
10
|
+
"passwordPlaceholder": "Bir ÅŸifre oluÅŸturun",
|
|
11
|
+
"confirmPassword": "Åžifre Tekrar",
|
|
12
|
+
"confirmPasswordPlaceholder": "Åžifrenizi tekrar girin",
|
|
13
|
+
"submit": "Hesap OluÅŸtur",
|
|
14
|
+
"submitting": "Hesap oluÅŸturuluyor...",
|
|
15
|
+
"hasAccount": "Zaten hesabınız var mı?",
|
|
16
|
+
"loginLink": "Giriş yapın",
|
|
17
|
+
"passwordMismatch": "Åžifreler eÅŸleÅŸmiyor",
|
|
18
|
+
"toastSuccessTitle": "Hesap oluÅŸturuldu!",
|
|
19
|
+
"toastSuccessDesc": "Lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.",
|
|
20
|
+
"toastErrorTitle": "Kayıt başarısız",
|
|
21
|
+
"errorGeneric": "Kayıt başarısız. Lütfen tekrar deneyin.",
|
|
22
|
+
"successTitle": "Hesap OluÅŸturuldu!",
|
|
23
|
+
"successMessage": "Giriş yapmadan önce lütfen hesabınızı doğrulamak için e-postanızı kontrol edin.",
|
|
24
|
+
"goToLogin": "Giriş Sayfasına Git"
|
|
25
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import axios, { type AxiosInstance, type AxiosResponse } from "axios";
|
|
2
|
+
import constants from "@/constants/constants.json";
|
|
3
|
+
|
|
4
|
+
// API service class
|
|
5
|
+
class ApiService {
|
|
6
|
+
private axiosInstance: AxiosInstance;
|
|
7
|
+
private settings: any = null;
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
// Default configuration - will be updated when settings load
|
|
11
|
+
this.axiosInstance = axios.create({
|
|
12
|
+
baseURL: "https://backend.promake.ai/api",
|
|
13
|
+
timeout: 30000,
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Request interceptor to add site slug
|
|
20
|
+
this.axiosInstance.interceptors.request.use(
|
|
21
|
+
(config) => {
|
|
22
|
+
if (this.settings?.site?.slug) {
|
|
23
|
+
config.headers["X-Site-Slug"] = this.settings.site.slug;
|
|
24
|
+
}
|
|
25
|
+
return config;
|
|
26
|
+
},
|
|
27
|
+
(error) => {
|
|
28
|
+
return Promise.reject(error);
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Response interceptor for error handling
|
|
33
|
+
this.axiosInstance.interceptors.response.use(
|
|
34
|
+
(response: AxiosResponse) => response,
|
|
35
|
+
(error) => {
|
|
36
|
+
console.error("API Error:", {
|
|
37
|
+
status: error.response?.status,
|
|
38
|
+
statusText: error.response?.statusText,
|
|
39
|
+
data: error.response?.data,
|
|
40
|
+
url: error.config?.url,
|
|
41
|
+
});
|
|
42
|
+
return Promise.reject(error);
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Update settings for API configuration
|
|
48
|
+
updateSettings(settings: any) {
|
|
49
|
+
this.settings = settings;
|
|
50
|
+
if (settings?.api?.baseUrl) {
|
|
51
|
+
this.axiosInstance.defaults.baseURL = settings.api.baseUrl;
|
|
52
|
+
}
|
|
53
|
+
if (settings?.api?.timeout) {
|
|
54
|
+
this.axiosInstance.defaults.timeout = settings.api.timeout;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Get endpoint from settings
|
|
59
|
+
private getEndpoint(key: string): string {
|
|
60
|
+
return this.settings?.api?.endpoints?.[key] || `/${key}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Order API methods
|
|
64
|
+
async createOrder(orderData: {
|
|
65
|
+
user_id: string;
|
|
66
|
+
total_price: number;
|
|
67
|
+
status: string;
|
|
68
|
+
payment_method: string;
|
|
69
|
+
shipping_address: any;
|
|
70
|
+
notes?: string | null;
|
|
71
|
+
items: Array<{
|
|
72
|
+
product_id: number;
|
|
73
|
+
quantity: number;
|
|
74
|
+
price: number;
|
|
75
|
+
}>;
|
|
76
|
+
}): Promise<{ orderId: number; success: boolean }> {
|
|
77
|
+
try {
|
|
78
|
+
const response = await this.axiosInstance.post(
|
|
79
|
+
this.getEndpoint("orders"),
|
|
80
|
+
{
|
|
81
|
+
site_slug: this.settings?.site?.slug || "promake",
|
|
82
|
+
order: {
|
|
83
|
+
user_id: orderData.user_id,
|
|
84
|
+
total_price: orderData.total_price,
|
|
85
|
+
status: orderData.status,
|
|
86
|
+
payment_method: orderData.payment_method,
|
|
87
|
+
shipping_address: orderData.shipping_address,
|
|
88
|
+
notes: orderData.notes,
|
|
89
|
+
},
|
|
90
|
+
items: orderData.items,
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
orderId: response.data.order_id,
|
|
96
|
+
success: true,
|
|
97
|
+
};
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
console.error("Order creation failed:", error);
|
|
100
|
+
throw new Error(error.response?.data?.message || "Order creation failed");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Generic form submission to mail service
|
|
105
|
+
async submitForm(
|
|
106
|
+
formData: Record<string, any>,
|
|
107
|
+
formConfig: {
|
|
108
|
+
email_subject1: string;
|
|
109
|
+
email_subject2: string;
|
|
110
|
+
fields: Array<{ name: string; required: boolean }>;
|
|
111
|
+
},
|
|
112
|
+
currentLanguage: string = "en",
|
|
113
|
+
): Promise<{ success: boolean; message: string }> {
|
|
114
|
+
try {
|
|
115
|
+
// Extract customer email from form data
|
|
116
|
+
const customerEmail = formData["email"];
|
|
117
|
+
if (!customerEmail) {
|
|
118
|
+
throw new Error("Email field is required in form data");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Get site owner email from ENV
|
|
122
|
+
const tenantEmail = import.meta.env.VITE_TENANT_MAIL;
|
|
123
|
+
if (!tenantEmail) {
|
|
124
|
+
throw new Error("VITE_TENANT_MAIL environment variable is not set");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Convert formData to backend expected format with required info from config
|
|
128
|
+
const data: Record<string, { required: boolean; value: any }> = {};
|
|
129
|
+
|
|
130
|
+
formConfig.fields.forEach((field) => {
|
|
131
|
+
data[field.name] = {
|
|
132
|
+
required: field.required,
|
|
133
|
+
value: formData[field.name] || null,
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Get mail service URL from ENV
|
|
138
|
+
const mailServiceUrl =
|
|
139
|
+
import.meta.env.VITE_MAIL_SERVICE_URL ||
|
|
140
|
+
"https://mail.promake.ai/api/v1/send-mail";
|
|
141
|
+
|
|
142
|
+
// Make request to mail service
|
|
143
|
+
const response = await axios.post(
|
|
144
|
+
mailServiceUrl,
|
|
145
|
+
{
|
|
146
|
+
target_email1: customerEmail,
|
|
147
|
+
target_email2: tenantEmail,
|
|
148
|
+
email_subject1: formConfig.email_subject1,
|
|
149
|
+
email_subject2: formConfig.email_subject2,
|
|
150
|
+
data: data,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
headers: {
|
|
154
|
+
"Accept-Language": currentLanguage,
|
|
155
|
+
"Content-Type": "application/json",
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
success: true,
|
|
162
|
+
message: response.data.message || "Form submitted successfully",
|
|
163
|
+
};
|
|
164
|
+
} catch (error: any) {
|
|
165
|
+
console.error("Form submission failed:", error);
|
|
166
|
+
throw new Error(error.response?.data?.message || "Failed to submit form");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// DEPRECATED: Use submitForm instead
|
|
171
|
+
// Keeping for backward compatibility
|
|
172
|
+
async submitContactForm(contactData: {
|
|
173
|
+
name: string;
|
|
174
|
+
email: string;
|
|
175
|
+
subject?: string;
|
|
176
|
+
message: string;
|
|
177
|
+
}): Promise<{ success: boolean; message: string }> {
|
|
178
|
+
console.warn("submitContactForm is deprecated. Use submitForm instead.");
|
|
179
|
+
return this.submitForm(
|
|
180
|
+
contactData,
|
|
181
|
+
{
|
|
182
|
+
email_subject1: "Contact Form Submission",
|
|
183
|
+
email_subject2: "New Contact Form",
|
|
184
|
+
fields: [
|
|
185
|
+
{ name: "name", required: true },
|
|
186
|
+
{ name: "email", required: true },
|
|
187
|
+
{ name: "subject", required: false },
|
|
188
|
+
{ name: "message", required: true },
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
"en",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Get order by ID (for order confirmation page)
|
|
196
|
+
async getOrderById(orderId: number): Promise<any | null> {
|
|
197
|
+
try {
|
|
198
|
+
const response = await this.axiosInstance.get(
|
|
199
|
+
`${this.getEndpoint("orders")}/${orderId}?site_slug=${
|
|
200
|
+
this.settings?.site?.slug
|
|
201
|
+
}`,
|
|
202
|
+
);
|
|
203
|
+
return response.data.order || null;
|
|
204
|
+
} catch (error: any) {
|
|
205
|
+
console.error("Failed to fetch order:", error);
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Create singleton instance
|
|
212
|
+
const apiService = new ApiService();
|
|
213
|
+
|
|
214
|
+
// Hook to use API service with settings
|
|
215
|
+
export const useApiService = () => {
|
|
216
|
+
// Reconstruct settings object for ApiService.updateSettings
|
|
217
|
+
const settings = {
|
|
218
|
+
site: {
|
|
219
|
+
slug: constants.site.slug,
|
|
220
|
+
},
|
|
221
|
+
api: {
|
|
222
|
+
baseUrl: constants.api.baseUrl,
|
|
223
|
+
timeout: constants.api.timeout,
|
|
224
|
+
endpoints: constants.api.endpoints,
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Update API service settings when they change
|
|
229
|
+
if (settings && apiService) {
|
|
230
|
+
apiService.updateSettings(settings);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return apiService;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// Export the service for direct use
|
|
237
|
+
export default apiService;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Site-specific localStorage utility
|
|
3
|
+
* Prevents localStorage conflicts between different templates on same domain
|
|
4
|
+
* Uses a unique site ID generated on first load
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
let sitePrefix: string | null = null;
|
|
8
|
+
const SITE_ID_KEY = "__site_id__"; // Raw key, no prefix
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate a unique site ID (UUID v4)
|
|
12
|
+
*/
|
|
13
|
+
const generateSiteId = (): string => {
|
|
14
|
+
return (
|
|
15
|
+
"site_" +
|
|
16
|
+
"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
17
|
+
const r = (Math.random() * 16) | 0;
|
|
18
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
19
|
+
return v.toString(16);
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get or create site-specific localStorage prefix
|
|
26
|
+
* Each site gets a unique ID on first load
|
|
27
|
+
*/
|
|
28
|
+
const getSitePrefix = (): string => {
|
|
29
|
+
if (sitePrefix) return sitePrefix;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Check if site already has a unique ID
|
|
33
|
+
let siteId = localStorage.getItem(SITE_ID_KEY);
|
|
34
|
+
|
|
35
|
+
if (!siteId) {
|
|
36
|
+
// First load - generate and save unique site ID
|
|
37
|
+
siteId = generateSiteId();
|
|
38
|
+
localStorage.setItem(SITE_ID_KEY, siteId);
|
|
39
|
+
console.log("🆔 Generated new site ID:", siteId);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
sitePrefix = siteId;
|
|
43
|
+
return sitePrefix;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("Failed to get/create site ID:", error);
|
|
46
|
+
// Fallback to timestamp-based ID
|
|
47
|
+
sitePrefix = "site_" + Date.now();
|
|
48
|
+
return sitePrefix;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get site-specific localStorage key
|
|
54
|
+
*/
|
|
55
|
+
export const getStorageKey = (key: string): string => {
|
|
56
|
+
const prefix = getSitePrefix();
|
|
57
|
+
return `${prefix}_${key}`;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get item from localStorage with site-specific key
|
|
62
|
+
*/
|
|
63
|
+
export const getItem = (key: string): string | null => {
|
|
64
|
+
try {
|
|
65
|
+
return localStorage.getItem(getStorageKey(key));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`Error reading from localStorage (${key}):`, error);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Set item to localStorage with site-specific key
|
|
74
|
+
*/
|
|
75
|
+
export const setItem = (key: string, value: string): void => {
|
|
76
|
+
try {
|
|
77
|
+
localStorage.setItem(getStorageKey(key), value);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(`Error writing to localStorage (${key}):`, error);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Remove item from localStorage with site-specific key
|
|
85
|
+
*/
|
|
86
|
+
export const removeItem = (key: string): void => {
|
|
87
|
+
try {
|
|
88
|
+
localStorage.removeItem(getStorageKey(key));
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(`Error removing from localStorage (${key}):`, error);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Clear all site-specific items from localStorage
|
|
96
|
+
*/
|
|
97
|
+
export const clearSiteStorage = (): void => {
|
|
98
|
+
try {
|
|
99
|
+
const prefix = getSitePrefix();
|
|
100
|
+
const keys = Object.keys(localStorage);
|
|
101
|
+
keys.forEach((key) => {
|
|
102
|
+
if (key.startsWith(`${prefix}_`)) {
|
|
103
|
+
localStorage.removeItem(key);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error("Error clearing site storage:", error);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { clsx, type ClassValue } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
export function cn(...inputs: ClassValue[]) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function formatPrice(price: number, currency: string = "USD"): string {
|
|
9
|
+
return new Intl.NumberFormat("en-US", {
|
|
10
|
+
style: "currency",
|
|
11
|
+
currency: currency,
|
|
12
|
+
minimumFractionDigits: 0,
|
|
13
|
+
maximumFractionDigits: 2,
|
|
14
|
+
}).format(price);
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "./lang";
|
|
2
|
+
import "./index.css";
|
|
3
|
+
import { StrictMode } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { Toaster } from "@/components/ui/sonner";
|
|
6
|
+
import App from "@/App.tsx";
|
|
7
|
+
|
|
8
|
+
createRoot(document.getElementById("root")!).render(
|
|
9
|
+
<StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
<Toaster />
|
|
12
|
+
</StrictMode>,
|
|
13
|
+
);
|