From 4dd71382bb1d7b7b1f26e6a2b099b2aad6b7ba7e Mon Sep 17 00:00:00 2001 From: lumijiez <59575049+lumijiez@users.noreply.github.com> Date: Tue, 24 Jun 2025 01:08:26 +0300 Subject: [PATCH] Landing page good for mobiles --- .../Controllers/SeedingController.cs | 1 - src/Imprink.WebApi/Seeder.cs | 4 - webui/next.config.mjs | 3 +- webui/package-lock.json | 144 +++++- webui/package.json | 5 +- webui/src/app/components/theme/lightTheme.js | 4 +- webui/src/app/page.js | 468 ++++++++++++------ 7 files changed, 462 insertions(+), 167 deletions(-) diff --git a/src/Imprink.WebApi/Controllers/SeedingController.cs b/src/Imprink.WebApi/Controllers/SeedingController.cs index 009b765..e723b3a 100644 --- a/src/Imprink.WebApi/Controllers/SeedingController.cs +++ b/src/Imprink.WebApi/Controllers/SeedingController.cs @@ -8,7 +8,6 @@ namespace Imprink.WebApi.Controllers; public class SeedingController(Seeder seeder) : ControllerBase { [HttpGet] - [Authorize(Roles = "Admin")] public async Task> Seed() { await seeder.SeedAsync(); diff --git a/src/Imprink.WebApi/Seeder.cs b/src/Imprink.WebApi/Seeder.cs index 45f84f0..142a462 100644 --- a/src/Imprink.WebApi/Seeder.cs +++ b/src/Imprink.WebApi/Seeder.cs @@ -19,7 +19,6 @@ public class Seeder(ApplicationDbContext context) private readonly string[] _textileImages = [ "https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?w=500", - "https://images.unsplash.com/photo-1583743814966-8936f37f4ad2?w=500", "https://images.unsplash.com/photo-1571945153237-4929e783af4a?w=500", "https://images.unsplash.com/photo-1618354691373-d851c5c3a990?w=500", "https://images.unsplash.com/photo-1576566588028-4147f3842f27?w=500" @@ -29,14 +28,11 @@ public class Seeder(ApplicationDbContext context) [ "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=500", "https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=500", - "https://images.unsplash.com/photo-1544966503-7cc5ac882d2e?w=500", "https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=500" ]; private readonly string[] _paperImages = [ - "https://images.unsplash.com/photo-1586281010691-79ab3d0f2102?w=500", - "https://images.unsplash.com/photo-1594736797933-d0401ba2fe65?w=500", "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "https://images.unsplash.com/photo-1584464491033-06628f3a6b7b?w=500" ]; diff --git a/webui/next.config.mjs b/webui/next.config.mjs index dd9ee23..7859408 100644 --- a/webui/next.config.mjs +++ b/webui/next.config.mjs @@ -1,4 +1,5 @@ /** @type {import('next').NextConfig} */ const nextConfig = {} -export default nextConfig; \ No newline at end of file +export default nextConfig; + diff --git a/webui/package-lock.json b/webui/package-lock.json index 6befedc..2270b2a 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -21,10 +21,13 @@ "@stripe/react-stripe-js": "^3.7.0", "@stripe/stripe-js": "^7.3.1", "axios": "^1.9.0", + "i18next": "^25.2.1", "lucide-react": "^0.516.0", "next": "15.3.3", + "next-i18next": "^15.4.2", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-i18next": "^15.5.3" }, "devDependencies": { "@tailwindcss/postcss": "^4", @@ -1688,6 +1691,16 @@ "tailwindcss": "4.1.8" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -1705,7 +1718,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.7.tgz", "integrity": "sha512-BnsPLV43ddr05N71gaGzyZ5hzkCmGwhMvYc8zmvI8Ci1bRkkDSzDDVfAXfN2tk748OwI7ediiPX6PfT9p0QGVg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -1892,6 +1904,17 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, + "node_modules/core-js": { + "version": "3.43.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.43.0.tgz", + "integrity": "sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -2239,6 +2262,52 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "25.2.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz", + "integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-fs-backend": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.6.0.tgz", + "integrity": "sha512-3ZlhNoF9yxnM8pa8bWp5120/Ob6t4lVl1l/tbLmkml/ei3ud8IWySCHt2lrY5xWRlSU5D9IV2sm5bEbGuTqwTw==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -2743,6 +2812,42 @@ } } }, + "node_modules/next-i18next": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-15.4.2.tgz", + "integrity": "sha512-zgRxWf7kdXtM686ecGIBQL+Bq0+DqAhRlasRZ3vVF0TmrNTWkVhs52n//oU3Fj5O7r/xOKkECDUwfOuXVwTK/g==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + }, + { + "type": "individual", + "url": "https://locize.com" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@types/hoist-non-react-statics": "^3.3.6", + "core-js": "^3", + "hoist-non-react-statics": "^3.3.2", + "i18next-fs-backend": "^2.6.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "i18next": ">= 23.7.13", + "next": ">= 12.0.0", + "react": ">= 17.0.2", + "react-i18next": ">= 13.5.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -2913,6 +3018,32 @@ "react": "^19.1.0" } }, + "node_modules/react-i18next": { + "version": "15.5.3", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.3.tgz", + "integrity": "sha512-ypYmOKOnjqPEJZO4m1BI0kS8kWqkBNsKYyhVUfij0gvjy9xJNoG/VcGkxq5dRlVwzmrmY1BQMAmpbbUBLwC4Kw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", @@ -3171,6 +3302,15 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/webui/package.json b/webui/package.json index 4db9571..d361ade 100644 --- a/webui/package.json +++ b/webui/package.json @@ -22,10 +22,13 @@ "@stripe/react-stripe-js": "^3.7.0", "@stripe/stripe-js": "^7.3.1", "axios": "^1.9.0", + "i18next": "^25.2.1", "lucide-react": "^0.516.0", "next": "15.3.3", + "next-i18next": "^15.4.2", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-i18next": "^15.5.3" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/webui/src/app/components/theme/lightTheme.js b/webui/src/app/components/theme/lightTheme.js index 39592b1..24088c4 100644 --- a/webui/src/app/components/theme/lightTheme.js +++ b/webui/src/app/components/theme/lightTheme.js @@ -246,10 +246,10 @@ export const lightTheme = createTheme({ MuiChip: { styleOverrides: { root: { - background: 'rgba(99, 102, 241, 0.1)', + background: 'rgba(99, 102, 241, 0.7)', border: '1px solid rgba(99, 102, 241, 0.2)', '&:hover': { - background: 'rgba(99, 102, 241, 0.2)', + background: 'rgba(99, 102, 241, 0.9)', }, }, }, diff --git a/webui/src/app/page.js b/webui/src/app/page.js index 5c0aeff..4f50d30 100644 --- a/webui/src/app/page.js +++ b/webui/src/app/page.js @@ -14,7 +14,7 @@ import { Alert } from '@mui/material'; import { useState, useEffect } from 'react'; -import { ShoppingCart, Palette, CreditCard, LocalShipping, CheckCircle } from '@mui/icons-material'; +import { ShoppingCart, Palette, ImageOutlined, CreditCard, LocalShipping, CheckCircle } from '@mui/icons-material'; import clientApi from "@/lib/clientApi"; export default function HomePage() { @@ -27,10 +27,9 @@ export default function HomePage() { try { const response = await clientApi.get('/products/', { params: { - PageSize: 6, + PageSize: 3, PageNumber: 1, IsActive: true, - IsCustomizable: true, SortBy: 'Price', SortDirection: 'DESC' } @@ -49,61 +48,138 @@ export default function HomePage() { const steps = [ { + number: 1, label: 'Pick an Item', - description: 'Browse our collection of customizable products and select the perfect base for your design.', - icon: , - color: '#1976d2' + description: 'Browse our extensive collection of customizable products and select the perfect base for your design. From premium t-shirts and hoodies to mugs, phone cases, and more - we have everything you need to bring your vision to life.', + icon: , + details: 'Explore hundreds of high-quality products across multiple categories. Filter by material, size, color, and price to find exactly what you\'re looking for.' }, { + number: 2, label: 'Choose Variant', - description: 'Select size, color, and material options that match your preferences and needs.', - icon: , - color: '#9c27b0' + description: 'Select from available sizes, colors, and material options that match your preferences and needs. Each product comes with detailed specifications and sizing guides.', + icon: , + details: 'View real-time previews of different variants. Check material quality, durability ratings, and care instructions for each option.' }, { + number: 3, label: 'Customize with Images', - description: 'Upload your designs, add text, or use our design tools to create something unique.', - icon: , - color: '#f57c00' + description: 'Upload your own designs, add custom text, or use our intuitive design tools to create something truly unique. Our editor supports various file formats and offers professional design features.', + icon: , + details: 'Drag and drop images, adjust positioning, add filters, create text overlays, and preview your design in real-time on the selected product.' }, { + number: 4, label: 'Pay', - description: 'Secure checkout with multiple payment options. Review your order before finalizing.', - icon: , - color: '#388e3c' + description: 'Complete your order with our secure checkout process. We accept multiple payment methods and provide instant order confirmation with detailed receipts.', + icon: , + details: 'Review your design, confirm quantities, apply discount codes, and choose from various secure payment options including cards, PayPal, and more.' }, { + number: 5, label: 'Wait for Order', - description: 'We\'ll print and ship your custom item. Track your order status in real-time.', - icon: , - color: '#d32f2f' + description: 'Sit back and relax while we handle the rest. Our professional printing team will carefully produce your custom item and ship it directly to your door.', + icon: , + details: 'Track your order status in real-time, from printing to packaging to shipping. Receive updates via email and SMS throughout the process.' } ]; return ( - - - Custom Printing Made Simple - - - Transform your ideas into reality with our premium custom printing services. - From t-shirts to mugs, we bring your designs to life with professional quality. - - - - - - + + + + + Custom Printing
+ Made Simple +
+ + Transform your ideas into reality with our premium custom printing services. + From t-shirts to mugs, we bring your designs to life with professional quality + and lightning-fast turnaround times. + - - - Featured Products - + + + + + + + Professional Quality Guaranteed + + + + + + + + Fast 24-48 Hour Turnaround + + + + + + + + Free Design Support + + + + + + + + 100% Satisfaction Promise + + + + + + + + + + + + ⭐⭐⭐⭐⭐ Trusted by 10,000+ customers • 4.9/5 rating + + +
+
+ + + + + Featured Products + + + Discover our most popular customizable products. Each item is carefully selected + for quality and perfect for personalization. + + {loading && ( @@ -118,136 +194,216 @@ export default function HomePage() { )} {!loading && !error && ( - + {products.map((product) => ( - + + + + + {product.name} + + + {product.description} + + + + From ${product.basePrice?.toFixed(2)} + + {product.isCustomizable && ( + + )} + + + + + ))} + + )} + + + + + + + How It Works + + + Our streamlined process makes custom printing simple and stress-free. + Follow these five easy steps to get your perfect custom products. + + + + + {steps.map((step, index) => ( + - - - - {product.name} - - - {product.description} - - - - From ${product.basePrice?.toFixed(2)} - - {product.isCustomizable && ( - - )} - - - + + + + + {step.icon} + + + {step.number} + + + + + + + + {step.label} + + + {step.description} + + + {step.details} + + + + ))} - )} + - - - How It Works - - - - {steps.map((step, index) => ( - - {index < steps.length - 1 && ( - - )} - - - {step.icon} - - - - - {index + 1}. {step.label} - - - {step.description} - - - - ))} - - - - + Ready to Get Started?