Compare commits

..

2 Commits

Author SHA1 Message Date
nabijonovdavronbek619@gmail.com
3dfce04ab0 fixed: image url, and updated form phone input validation 2025-12-26 15:15:39 +05:00
nabijonovdavronbek619@gmail.com
ca80c6920c for github 2025-12-25 18:16:52 +05:00
6 changed files with 68 additions and 42 deletions

View File

@@ -12,6 +12,7 @@ export function ContactForm() {
const { t } = useLanguage();
const productName = useProductStore((state) => state.productName);
const reset = useProductStore((state) => state.resetProductName);
const [formData, setFormData] = useState({
name: "",
@@ -26,15 +27,29 @@ export function ContactForm() {
text: string;
} | null>(null);
const phoneRegex = /^\+?\d*$/; // + majburiy
const handleChange = (
e: React.ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>
) => {
const { name, value } = e.target;
if (name === "phone") {
// regexga mos kelmasa — state ozgarmaydi
if (!phoneRegex.test(value)) return;
setFormData((prev) => ({
...prev,
[e.target.name]: e.target.value,
phone: value,
}));
} else {
setFormData((prev) => ({
...prev,
[name]: value,
}));
}
};
const handleSubmit = async (e: React.FormEvent) => {
@@ -62,6 +77,8 @@ ${formData.message || "—"}
text: text,
});
setMessage({ type: "success", text: t.contact.success });
reset();
setFormData({ name: "", phone: "", message: "", productName: "" });
} catch {
setMessage({ type: "error", text: t.contact.error });
} finally {
@@ -168,7 +185,7 @@ ${formData.message || "—"}
value={formData.name}
onChange={handleChange}
placeholder={t.contact.namePlaceholder}
className="w-full px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full text-black px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
@@ -184,7 +201,7 @@ ${formData.message || "—"}
onChange={handleChange}
placeholder={t.contact.phonePlaceholder}
required
className="w-full px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full text-black px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
@@ -199,7 +216,7 @@ ${formData.message || "—"}
onChange={handleChange}
placeholder={t.contact.messagePlaceholder}
rows={4}
className="w-full px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
className="w-full text-black px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
/>
</div>
@@ -214,7 +231,7 @@ ${formData.message || "—"}
value={productName ? productName : formData.productName}
onChange={handleChange}
placeholder={t.contact.product}
className="w-full px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full text-black px-4 py-2 border border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>

View File

@@ -29,7 +29,7 @@ export function ProductCard({ product, onViewDetails }: ProductCardProps) {
className="w-full h-full"
>
<img
src={`https://api.serenmebel.uz${product.image}`}
src={`https://admin.promtechno.uz${product.image}`}
alt={languageIndex?product.name_uz:product.name_ru}
className="w-full h-full object-cover"
/>

View File

@@ -61,7 +61,7 @@ export function ProductModal({ product, onClose }: ProductModalProps) {
{/* Image */}
<div className="relative max-sm:w-full max-md:h-50">
<Image
src={`https://api.serenmebel.uz${product.image}`}
src={`https://admin.promtechno.uz${product.image}`}
alt="image"
fill
className="object-contain max-md:h-50"

View File

@@ -10,6 +10,7 @@ import { ChevronsRight } from "lucide-react";
import { ProductCard } from "./ProductCard";
import { ProductModal } from "./ProductModal";
import axios from "axios";
import EmptyState from "../productsPage/emptyData";
// hello everyone
@@ -20,10 +21,12 @@ export function ProductsGrid() {
useEffect(() => {
async function getData() {
await axios.get("https://admin.promtechno.uz/api/products/").then((res) => {
await axios
.get("https://admin.promtechno.uz/api/products/")
.then((res) => {
console.log("all data main page: ", res?.data);
const allData = res?.data || [];
setAllProducts(allData.slice(0,3));
setAllProducts(allData.slice(0, 3));
});
}
getData();
@@ -64,6 +67,7 @@ export function ProductsGrid() {
</motion.div>
{/* Product Grid */}
{allProducts && allProducts.length > 0 ? (
<motion.div
initial="hidden"
whileInView="visible"
@@ -71,7 +75,7 @@ export function ProductsGrid() {
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
>
{allProducts.map((product: any) => (
<motion.div key={product.id} >
<motion.div key={product.id}>
<ProductCard
product={product}
onViewDetails={handleViewDetails}
@@ -79,6 +83,9 @@ export function ProductsGrid() {
</motion.div>
))}
</motion.div>
) : (
<EmptyState page="main" />
)}
</div>
<div className="mt-10 w-full flex items-center justify-center">
<Link
@@ -90,7 +97,7 @@ export function ProductsGrid() {
</div>
</section>
{/* Product Modal */}
{/* Product Modalll */}
{selectedProduct && (
<ProductModal
product={selectedProduct}

View File

@@ -7,7 +7,7 @@ import { useLanguage } from "@/context/language-context";
//salomalr
export default function EmptyState() {
export default function EmptyState({page}:{page: string}) {
const { t } = useLanguage();
const container = {
@@ -23,7 +23,7 @@ export default function EmptyState() {
animate="show"
variants={container}
>
<div className="max-w-5xl w-full bg-white/60 bg-linear-to-br from-primary to-gray-800 backdrop-blur-md rounded-2xl shadow-lg overflow-hidden">
<div className="max-w-5xl w-full bg-linear-to-br from-primary via-primary/50 to-gray-300 backdrop-blur-md rounded-2xl shadow-lg overflow-hidden">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-center p-8 md:p-12">
{/* Illustration / Icon */}
<motion.div className="flex items-center justify-center">
@@ -54,6 +54,7 @@ export default function EmptyState() {
{t.empty_data.description}
</p>
{page !== "main" && (
<div className="mt-6 flex flex-col sm:flex-row items-center sm:items-start gap-3 md:gap-4 justify-center md:justify-start">
<motion.div
className="inline-flex items-center justify-center px-5 py-2.5 bg-primary/70 hover:bg-primary text-white rounded-lg shadow-md transition-colors text-sm font-medium"
@@ -62,6 +63,7 @@ export default function EmptyState() {
<Link href="/">{t.empty_data.back || "Bosh sahifa"}</Link>
</motion.div>
</div>
)}
</motion.div>
</div>
</div>

View File

@@ -46,7 +46,7 @@ export default function Products() {
))}
</div>
) : (
<EmptyState />
<EmptyState page="products" />
)}
{/* Product Modal */}
{selectedProduct && (