fixed some errors

This commit is contained in:
@jcarymuhammedow
2026-01-08 18:01:17 +05:00
parent 7538bdb813
commit 071b45b98a
15 changed files with 1809 additions and 727 deletions

View File

@@ -121,20 +121,22 @@
}
}
[data-sonner-toast] [data-description] {
color: #000 !important;
opacity: 0.9;
}
/* Animasyonları "utilities" katmanına ekliyoruz ki Tailwind sınıfları gibi davranabilsinler */
@layer utilities {
/* Özel Renk Sınıfları (CSS değişkenlerini kullanmak için) */
.text-fg { color: var(--fg); }
.bg-bg { background-color: var(--bg); }
.stroke-primary { stroke: #005bff; }
/* Dark mode track rengi için özel sınıf */
.text-fg {
color: var(--fg);
}
.bg-bg {
background-color: var(--bg);
}
.stroke-primary {
stroke: #005bff;
}
.stroke-track {
stroke: hsla(var(--hue), 10%, 10%, 0.1);
transition: stroke var(--trans-dur);
@@ -145,48 +147,90 @@
}
}
/* Animasyon Sınıfları */
.animate-msg { animation: msg 0.3s 13.7s linear forwards; }
.animate-msgLast { animation: msg 0.3s 14s linear reverse forwards; }
.animate-cartLines { animation: cartLines 2s ease-in-out infinite; }
.animate-cartTop { animation: cartTop 2s ease-in-out infinite; }
.animate-cartWheel1 {
.animate-msg {
animation: msg 0.3s 13.7s linear forwards;
}
.animate-msgLast {
animation: msg 0.3s 14s linear reverse forwards;
}
.animate-cartLines {
animation: cartLines 2s ease-in-out infinite;
}
.animate-cartTop {
animation: cartTop 2s ease-in-out infinite;
}
.animate-cartWheel1 {
animation: cartWheel1 2s ease-in-out infinite;
transform: rotate(-0.25turn);
transform-origin: 43px 111px;
}
.animate-cartWheel2 {
.animate-cartWheel2 {
animation: cartWheel2 2s ease-in-out infinite;
transform: rotate(0.25turn);
transform-origin: 102px 111px;
}
.animate-cartWheelStroke { animation: cartWheelStroke 2s ease-in-out infinite; }
.animate-cartWheelStroke {
animation: cartWheelStroke 2s ease-in-out infinite;
}
}
/* Keyframes Tanımları */
@keyframes msg {
from { opacity: 1; visibility: visible; }
99.9% { opacity: 0; visibility: visible; }
to { opacity: 0; visibility: hidden; }
from {
opacity: 1;
visibility: visible;
}
99.9% {
opacity: 0;
visibility: visible;
}
to {
opacity: 0;
visibility: hidden;
}
}
@keyframes cartLines {
from, to { opacity: 0; }
8%, 92% { opacity: 1; }
from,
to {
opacity: 0;
}
8%,
92% {
opacity: 1;
}
}
@keyframes cartTop {
from { stroke-dashoffset: -338; }
50% { stroke-dashoffset: 0; }
to { stroke-dashoffset: 338; }
from {
stroke-dashoffset: -338;
}
50% {
stroke-dashoffset: 0;
}
to {
stroke-dashoffset: 338;
}
}
@keyframes cartWheel1 {
from { transform: rotate(-0.25turn); }
to { transform: rotate(2.75turn); }
from {
transform: rotate(-0.25turn);
}
to {
transform: rotate(2.75turn);
}
}
@keyframes cartWheel2 {
from { transform: rotate(0.25turn); }
to { transform: rotate(3.25turn); }
from {
transform: rotate(0.25turn);
}
to {
transform: rotate(3.25turn);
}
}
@keyframes cartWheelStroke {
from, to { stroke-dashoffset: 81.68; }
50% { stroke-dashoffset: 40.84; }
}
from,
to {
stroke-dashoffset: 81.68;
}
50% {
stroke-dashoffset: 40.84;
}
}

View File

@@ -54,10 +54,7 @@ interface FormErrors {
file?: string;
}
export default function OpenStorePage({
locale = "ru",
translations,
}: OpenStorePageProps) {
export default function OpenStorePage({}: OpenStorePageProps) {
const [formData, setFormData] = useState<FormData>({
firstName: "",
lastName: "",
@@ -76,21 +73,21 @@ export default function OpenStorePage({
const newErrors: FormErrors = {};
if (!formData.firstName.trim()) {
newErrors.firstName = t("firstNameRequired");
newErrors.firstName = t("requiredField");
}
if (!formData.lastName.trim()) {
newErrors.lastName = t("lastNameRequired");
newErrors.lastName = t("requiredField");
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(formData.email)) {
newErrors.email = t("emailInvalid");
newErrors.email = t("requiredField");
}
const phoneRegex = /^\+?[0-9]{6,15}$/;
if (!phoneRegex.test(formData.phone)) {
newErrors.phone = t("phoneInvalid");
newErrors.phone = t("requiredField");
}
if (!formData.file) {

View File

@@ -46,11 +46,10 @@ export default function ErrorPage() {
return (
<div className="min-h-screen bg-white flex flex-col items-center justify-start overflow-hidden font-['Encode_Sans_Semi_Condensed',_sans-serif]">
{/* CSS Animasyonlarını buraya gömüyoruz */}
<style dangerouslySetInnerHTML={{ __html: fontImport }} />
<h1
className={`text-[10rem] leading-[10rem] font-extralight text-black transition-all duration-500 ease-linear
className={`text-[10rem] leading-40 font-extralight text-black transition-all duration-500 ease-linear
${isLoading ? "mt-0 opacity-0" : "mt-[100px] opacity-100"}`}
>
500
@@ -110,7 +109,6 @@ export default function ErrorPage() {
);
}
// Dişli çubukları için yardımcı bileşen
function GearBars() {
return (
<>

View File

@@ -1,4 +1,4 @@
"use client"
"use client";
import {
CircleCheckIcon,
@@ -6,12 +6,12 @@ import {
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, type ToasterProps } from "sonner"
} from "lucide-react";
import { useTheme } from "next-themes";
import { Toaster as Sonner, type ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
const { theme = "system" } = useTheme();
return (
<Sonner
@@ -24,17 +24,24 @@ const Toaster = ({ ...props }: ToasterProps) => {
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
}}
toastOptions={{
classNames: {
description: "text-foreground opacity-90",
title: "font-bold",
},
}}
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
"--border-radius": "var(--radius)",
"--description-color": "var(--popover-foreground)",
} as React.CSSProperties
}
{...props}
/>
)
}
);
};
export { Toaster }
export { Toaster };

View File

@@ -155,7 +155,7 @@ export default function OrderSummary({
}`}
/>
{showValidation && name.trim() === "" && (
<p className="text-xs text-red-500 mt-1">Bu alan zorunludur</p>
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
<div>
@@ -172,7 +172,7 @@ export default function OrderSummary({
}`}
/>
{showValidation && lastName.trim() === "" && (
<p className="text-xs text-red-500 mt-1">Bu alan zorunludur</p>
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
<div>
@@ -190,7 +190,7 @@ export default function OrderSummary({
/>
{showValidation && !isPhoneValid && (
<p className="text-xs text-red-500 mt-1">
Telefon 8 rakamdan oluşmalıdır
{t("requiredField")}
</p>
)}
</div>
@@ -226,7 +226,7 @@ export default function OrderSummary({
))}
</div>
{showValidation && !paymentType && (
<p className="text-xs text-red-500 mt-1">Ödeme türü seçiniz</p>
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
@@ -264,7 +264,7 @@ export default function OrderSummary({
))}
</RadioGroup>
{showValidation && !selectedRegion && (
<p className="text-xs text-red-500 mt-1">Bölge seçiniz</p>
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
@@ -294,7 +294,7 @@ export default function OrderSummary({
</SelectContent>
</Select>
{showValidation && !selectedProvince && (
<p className="text-xs text-red-500 mt-1">Adres seçiniz</p>
<p className="text-xs text-red-500 mt-1">{t("requiredField")}</p>
)}
</div>
)}

View File

@@ -382,7 +382,7 @@ export default function ProductCard({
) : (
<>
<ShoppingCart className="h-4 w-4" />
{t("checkout")}
{t("add_to_cart")}
</>
)}
</Button>

View File

@@ -111,7 +111,7 @@ export function ProductInfoCard({
</Card>
{description && (
<Card className="p-4 rounded-xl border-gray-200">
<Card className="p-4 rounded-xl border-gray-200 gap-2">
<h3 className="text-xl font-semibold mb-3">
{t("product_description")}
</h3>

View File

@@ -119,6 +119,24 @@ export default function ProductPageContent({ slug }: ProductDetailProps) {
[product]
);
const transformedRelatedProducts = useMemo(() => {
if (!relatedProducts) return [];
return relatedProducts.map((p) => ({
id: p.id,
slug: p.slug,
name: p.name,
price_amount: p.price_amount,
old_price_amount: p.old_price_amount ?? undefined,
struct_price_text: `${p.price_amount} TMT`,
discount: null,
discount_text: null,
stock: p.stock,
media: p.media,
labels: [],
price_color: undefined,
}));
}, [relatedProducts]);
useEffect(() => {
if (!product?.id || isInitialized) return;
@@ -246,7 +264,7 @@ export default function ProductPageContent({ slug }: ProductDetailProps) {
}
} catch (error) {
setLocalQuantity(cartItem?.product_quantity || 1);
toast.error("Failed to update quantity", {
toast.error(t("failed_to_update_quantity"), {
description: "Please try again",
});
@@ -438,10 +456,10 @@ export default function ProductPageContent({ slug }: ProductDetailProps) {
/>
<ProductInfoCard
brandName={product.brand?.name}
brandName={product.brand?.name ?? undefined}
stock={product.stock}
barcode={product.barcode}
colour={product.colour}
colour={product.colour ?? undefined}
properties={product.properties}
description={product.description}
averageRating={averageRating}
@@ -451,7 +469,7 @@ export default function ProductPageContent({ slug }: ProductDetailProps) {
<ProductPurchaseCard
price={product.price_amount}
oldPrice={product.old_price_amount}
oldPrice={product.old_price_amount ?? undefined}
isInCart={isInCart}
localQuantity={localQuantity}
availableStock={availableStock}
@@ -475,7 +493,7 @@ export default function ProductPageContent({ slug }: ProductDetailProps) {
onWriteReview={() => setShowReviewModal(true)}
/>
<RelatedProductsSection products={relatedProducts || []} />
<RelatedProductsSection products={transformedRelatedProducts} />
</div>
<StockLimitModal

View File

@@ -45,9 +45,7 @@ export function ProductPurchaseCard({
<div className="flex justify-between items-start mb-6">
<span className="text-lg text-gray-500">{t("price")}:</span>
<div className="flex flex-col items-end">
<span className="text-3xl font-bold text-primary">
{price} TMT
</span>
<span className="text-3xl font-bold text-primary">{price} TMT</span>
{oldPrice && parseFloat(oldPrice) > 0 && (
<span className="text-lg text-gray-400 line-through">
{oldPrice} TMT
@@ -102,6 +100,7 @@ export function ProductPurchaseCard({
<Plus className="h-5 w-5" />
</Button>
<Button
variant="outline"
size="icon"
@@ -123,24 +122,43 @@ export function ProductPurchaseCard({
</div>
</>
) : (
<Button
size="lg"
onClick={onAddToCart}
disabled={isSyncing || productStock === 0}
className="w-full rounded-lg text-lg font-bold bg-[#005bff] hover:bg-[#0041c4] cursor-pointer"
>
{isSyncing ? (
<>
{t("adding")}
</>
) : (
<>
<ShoppingCart className="mr-2 h-5 w-5" />
{productStock === 0 ? t("out_of_stock") : t("add_to_cart")}
</>
)}
</Button>
<div className="flex items-center gap-2">
<Button
size="lg"
onClick={onAddToCart}
disabled={isSyncing || productStock === 0}
className="flex-1 rounded-lg text-lg font-bold bg-[#005bff] hover:bg-[#0041c4] cursor-pointer"
>
{isSyncing ? (
<>{t("adding")}</>
) : (
<>
<ShoppingCart className="mr-2 h-5 w-5" />
{productStock === 0 ? t("out_of_stock") : t("add_to_cart")}
</>
)}
</Button>
<Button
variant="outline"
size="icon"
onClick={onToggleFavorite}
className={`rounded-lg h-12 w-12 transition-all border cursor-pointer ${
isFavorite
? "bg-[#F0F8FF] border-blue-300 hover:bg-blue-100"
: "hover:bg-gray-50"
}`}
>
<Heart
className={`h-6! w-6! transition-all ${
isFavorite
? "fill-[#005bff] text-[#005bff]"
: "text-[#005bff]"
}`}
/>
</Button>
</div>
)}
</div>
</Card>
@@ -158,11 +176,15 @@ export function ProductPurchaseCard({
<h4 className="text-lg font-bold">{channelName}</h4>
</div>
</div>
<Button variant="outline" size="lg" className="w-full cursor-pointer rounded-lg">
<Button
variant="outline"
size="lg"
className="w-full cursor-pointer rounded-lg"
>
{t("write_to_store")}
</Button>
</Card>
)}
</div>
);
}
}

View File

@@ -78,7 +78,7 @@ export default function ClientProfilePage(props: ProfilePageProps) {
const handleSave = useCallback(async () => {
if (!formData.name.trim()) {
toast.error(t("name_required") || "Name is required");
toast.error(t("requiredField") || "Name is required");
return;
}

View File

@@ -33,9 +33,6 @@
"address_search": "Поиск адреса",
"address": "Адрес",
"first_name": "Имя",
"building": "Дом",
"floor": "Этаж",
"apartment": "Кв",
"save": "Сохранить",
"enter_phone": "Введите свой номер телефона",
"code_will_be_sent": "Мы вышлем вам код",
@@ -102,6 +99,7 @@
"empty_favorites": "У вас пока нет избранных товаров",
"removed_from_favorites": "Товар удален из избранного",
"added_to_cart": "Товар добавлен в корзину",
"failed_to_update_quantity": "Количество не удалось обновить",
"removed_from_cart": "Товар удален из корзины",
"error": "Произошла ошибка",
"out_of_stock": "Нет в наличии",
@@ -190,7 +188,9 @@
"title": "Открыть магазин",
"enter_email": "Введите email",
"uploadPatent": "Загрузить патент",
"outOfStock": "Нет в наличии"
"outOfStock": "Нет в наличии",
"requiredField": "Обязательное поле",
"fileRequired": "Файл загрузить"
}

View File

@@ -33,9 +33,6 @@
"address_search": "Adres gözleg",
"address": "Adres",
"first_name": "Ady",
"building": "Jaý",
"floor": "Gat",
"apartment": "Otag",
"save": "Ýatda sakla",
"enter_phone": "Telefon belgisini giriziň",
"code_will_be_sent": "Biz size kod ugradarys",
@@ -78,7 +75,7 @@
"no": "Ýok",
"yes": "Hawa",
"cart_empty": "Siziň söwda sebediňiz boş",
"add_to_cart": "Söwda sebedine üstünlikli goşuldy",
"add_to_cart": "Sebede goş",
"go_to_cart": "Sebede geçmek",
"products": "Azyk harytlary",
@@ -103,6 +100,7 @@
"empty_favorites": "Siziň saýlanan harytlaryňyz ýok",
"removed_from_favorites": "Haryt saýlanlardan aýryldy",
"added_to_cart": "Haryt sebede goşuldy",
"failed_to_update_quantity": "Mukdar täzelenip bolmady",
"removed_from_cart": "Haryt sebetden aýryldy",
"error": "Ýalňyşlyk ýüze çykdy",
"out_of_stock": "Haryt ýok",
@@ -191,5 +189,7 @@
"title": "Magazin aç",
"enter_email": "Poçtaňyzy ýazyň",
"uploadPatent": "Patent goş",
"outOfStock": "Ammarda ýok"
"outOfStock": "Ammarda ýok",
"requiredField": "Zerur maglumat",
"fileRequired": "Fayl goş"
}

View File

@@ -19,6 +19,7 @@ class APIClient {
constructor() {
this.baseUrl = process.env.NEXT_PUBLIC_API_URL || "https://api.example.com";
console.log("API URL:", this.baseUrl);
this.client = axios.create({
baseURL: `${this.baseUrl}/api/v1`,
@@ -42,7 +43,7 @@ class APIClient {
}
// Add language parameter
let lang = "tk";
let lang = "tm";
if (typeof window !== "undefined") {
if ((window as any).i18n?.language) {

View File

@@ -5,7 +5,7 @@ const withNextIntl = createNextIntlPlugin("./i18n/i18n.ts")
const nextConfig: NextConfig = {
typescript: {
ignoreBuildErrors: true,
ignoreBuildErrors: false,
},
images: {
unoptimized: true,

2243
package-lock.json generated

File diff suppressed because it is too large Load Diff