Create file constant

This commit is contained in:
hamid zarghami
2025-12-03 09:08:48 +03:30
parent 20e6f2e6f6
commit 975e29bbc9
9 changed files with 76 additions and 42 deletions
-5
View File
@@ -4,11 +4,6 @@ import withPWA from "next-pwa";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: "standalone", output: "standalone",
poweredByHeader: false, poweredByHeader: false,
env: {
NEXT_PUBLIC_API_BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL,
NEXT_PUBLIC_TOKEN_NAME: process.env.NEXT_PUBLIC_TOKEN_NAME,
NEXT_PUBLIC_REFRESH_TOKEN_NAME: process.env.NEXT_PUBLIC_REFRESH_TOKEN_NAME,
},
images: { images: {
remotePatterns: [ remotePatterns: [
{ {
@@ -1,32 +1,67 @@
'use client'; 'use client';
import { useGetAddresses } from '@/app/[name]/(Profile)/profile/address/hooks/useAddressData'; import { useGetAddresses } from '@/app/[name]/(Profile)/profile/address/hooks/useAddressData';
import { Address } from '@/app/[name]/(Profile)/profile/address/types/Types';
import PrimaryButton from '@/components/button/PrimaryButton';
import { ChevronLeft } from 'lucide-react'; import { ChevronLeft } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
type AddressSectionProps = { const formatAddress = (address: Address) => {
address: string; return `${address.address}، ${address.city}، ${address.province}`;
}; };
export const AddressSection = ({ address }: AddressSectionProps) => { export const AddressSection = () => {
const params = useParams<{ name: string; id: string }>(); const params = useParams<{ name: string; id: string }>();
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' }); const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
const { data: addresses } = useGetAddresses(); const { data: addressesResponse, isLoading } = useGetAddresses();
const addresses = addressesResponse?.data || [];
const redirectUrl = `/${params.name}/order/checkout/${params.id}`;
console.log(addresses); // اگر در حال بارگذاری است، چیزی نمایش نده
if (isLoading) {
return null;
}
// اگر آدرس ندارد
if (addresses.length === 0) {
return (
<section className="bg-container rounded-container box-shadow-normal p-4">
<div className="py-3">
<h3 className="text-sm2 font-medium leading-5 mb-4">{t("SectionAddress.Title")}</h3>
<p className='text-sm2 text-disabled-text mb-4'>
آدرسی ثبت نشده است
</p>
<Link href={`/${params.name}/profile/address/new?redirect=${encodeURIComponent(redirectUrl)}`}>
<PrimaryButton>
افزودن آدرس جدید
</PrimaryButton>
</Link>
</div>
</section>
);
}
// فیلتر کردن آدرس‌های غیر پیش‌فرض
const nonDefaultAddresses = addresses.filter(addr => !addr.isDefault);
// اگر فقط آدرس پیش‌فرض دارد، نمایش نده
if (nonDefaultAddresses.length === 0) {
return null;
}
// آدرس اول غیر پیش‌فرض را نمایش بده
const firstNonDefaultAddress = nonDefaultAddresses[0];
return ( return (
<section className="bg-container rounded-container box-shadow-normal p-4"> <section className="bg-container rounded-container box-shadow-normal p-4">
<div className="py-3"> <div className="py-3">
<div className='w-full flex justify-between items-center gap-2'> <div className='w-full flex justify-between items-center gap-2'>
<h3 className="text-sm2 font-medium leading-5 inline-block">{t("SectionAddress.Title")}</h3> <h3 className="text-sm2 font-medium leading-5 inline-block">{t("SectionAddress.Title")}</h3>
<Link href={`/${params.name}/profile/address?redirect=/${params.name}/order/checkout/${params.id}`}> <Link href={`/${params.name}/profile/address?redirect=${encodeURIComponent(redirectUrl)}`}>
<button <button
className='text-sm2 text-primary dark:text-foreground cursor-pointer' className='text-sm2 text-primary dark:text-foreground cursor-pointer'
onClick={() => { /* Handle address change */ }}
> >
{t("SectionAddress.ButtonChangeAddress")} {t("SectionAddress.ButtonChangeAddress")}
<ChevronLeft className='inline-block mr-1 mb-0.5 stroke-primary dark:stroke-foreground' size='16' /> <ChevronLeft className='inline-block mr-1 mb-0.5 stroke-primary dark:stroke-foreground' size='16' />
@@ -34,7 +69,7 @@ export const AddressSection = ({ address }: AddressSectionProps) => {
</Link> </Link>
</div> </div>
<p className='mt-6 text-sm2'> <p className='mt-6 text-sm2'>
{address} {formatAddress(firstNonDefaultAddress)}
</p> </p>
</div> </div>
</section> </section>
@@ -17,7 +17,6 @@ function OrderDetailInex() {
const [couponCode, setCouponCode] = React.useState<string>(''); const [couponCode, setCouponCode] = React.useState<string>('');
const [couponCodeError, setCouponCodeError] = React.useState<string>(''); const [couponCodeError, setCouponCodeError] = React.useState<string>('');
const [tableNumber, setTableNumber] = useState(0); const [tableNumber, setTableNumber] = useState(0);
const address = "اراک، مصطفی خمینی، خیابان سینا کوچه چمران ساختمان شهرزاد";
const { state: cartModal, toggle: toggleCartModal } = useToggle(); const { state: cartModal, toggle: toggleCartModal } = useToggle();
const incrementTableNumber = () => setTableNumber((prev) => prev + 1); const incrementTableNumber = () => setTableNumber((prev) => prev + 1);
@@ -51,7 +50,7 @@ function OrderDetailInex() {
/> />
{deliveryType === '0' && ( {deliveryType === '0' && (
<AddressSection address={address} /> <AddressSection />
)} )}
{deliveryType === '1' && ( {deliveryType === '1' && (
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import { useCreateAddress, useUpdateAddress } from '../../hooks/useAddressData'; import { useCreateAddress, useUpdateAddress } from '../../hooks/useAddressData';
import { toast } from '@/components/Toast'; import { toast } from '@/components/Toast';
import { CreateAddressType, UpdateAddressType, NominatimReverseGeocodingResponse, Address } from '../../types/Types'; import { CreateAddressType, UpdateAddressType, NominatimReverseGeocodingResponse, Address } from '../../types/Types';
@@ -20,6 +20,8 @@ export const useAddressForm = ({
addressData = null, addressData = null,
}: UseAddressFormProps) => { }: UseAddressFormProps) => {
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams();
const redirect = searchParams.get('redirect');
const { mutate: createAddress, isPending: isCreating } = useCreateAddress(); const { mutate: createAddress, isPending: isCreating } = useCreateAddress();
const { mutate: updateAddress, isPending: isUpdating } = useUpdateAddress(); const { mutate: updateAddress, isPending: isUpdating } = useUpdateAddress();
const isPending = isCreating || isUpdating; const isPending = isCreating || isUpdating;
@@ -92,7 +94,11 @@ export const useAddressForm = ({
updateAddress(updateData, { updateAddress(updateData, {
onSuccess: () => { onSuccess: () => {
toast('آدرس با موفقیت به‌روزرسانی شد', 'success'); toast('آدرس با موفقیت به‌روزرسانی شد', 'success');
router.back(); if (redirect) {
router.replace(redirect);
} else {
router.back();
}
}, },
onError: (error) => { onError: (error) => {
const errorMessage = error instanceof Error ? error.message : 'خطا در به‌روزرسانی آدرس'; const errorMessage = error instanceof Error ? error.message : 'خطا در به‌روزرسانی آدرس';
@@ -105,7 +111,11 @@ export const useAddressForm = ({
createAddress(createData, { createAddress(createData, {
onSuccess: () => { onSuccess: () => {
toast('آدرس با موفقیت ثبت شد', 'success'); toast('آدرس با موفقیت ثبت شد', 'success');
router.back(); if (redirect) {
router.replace(redirect);
} else {
router.back();
}
}, },
onError: (error) => { onError: (error) => {
const errorMessage = error instanceof Error ? error.message : 'خطا در ثبت آدرس'; const errorMessage = error instanceof Error ? error.message : 'خطا در ثبت آدرس';
+3
View File
@@ -0,0 +1,3 @@
export const API_BASE_URL = "https://dmenuplus-api.dev.danakcorp.com";
export const TOKEN_NAME = "dmenu-t";
export const REFRESH_TOKEN_NAME = "dmenu-rt";
+3 -2
View File
@@ -10,6 +10,7 @@ import Button from '@/components/button/PrimaryButton'
import { extractErrorMessage } from '@/lib/func' import { extractErrorMessage } from '@/lib/func'
import { useReceiptStore } from '@/zustand/receiptStore' import { useReceiptStore } from '@/zustand/receiptStore'
import { useBulkCart } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData' import { useBulkCart } from '@/app/[name]/(Dialogs)/cart/hooks/useCartData'
import { setRefreshToken, setToken } from '@/lib/api/func'
type Props = { type Props = {
@@ -38,8 +39,8 @@ const StepOtp = ({ phone, slug }: Props) => {
mutateOtpVerify(values, { mutateOtpVerify(values, {
onSuccess: (data) => { onSuccess: (data) => {
toast(t('otp_verified'), 'success') toast(t('otp_verified'), 'success')
localStorage.setItem(process.env.NEXT_PUBLIC_TOKEN_NAME as string, data?.data?.tokens?.accessToken?.token as string) setToken(data?.data?.tokens?.accessToken?.token as string)
localStorage.setItem(process.env.NEXT_PUBLIC_REFRESH_TOKEN_NAME as string, data?.data?.tokens?.refreshToken?.token as string) setRefreshToken(data?.data?.tokens?.refreshToken?.token as string)
if (Object.keys(items).length > 0) { if (Object.keys(items).length > 0) {
const bulkCartItems = Object.entries(items).map(([key, value]) => { const bulkCartItems = Object.entries(items).map(([key, value]) => {
+2 -1
View File
@@ -1,4 +1,5 @@
import axios from "axios"; import axios from "axios";
import { API_BASE_URL } from "@/config/const";
export type RefreshTokenRequestModel = { export type RefreshTokenRequestModel = {
token: string; token: string;
@@ -6,7 +7,7 @@ export type RefreshTokenRequestModel = {
export const refreshToken = async (model: RefreshTokenRequestModel) => { export const refreshToken = async (model: RefreshTokenRequestModel) => {
const res = await axios.post( const res = await axios.post(
`${process.env.NEXT_PUBLIC_API_BASE_URL}/public/auth/refresh`, `${API_BASE_URL}/public/auth/refresh`,
{ refreshToken: model.token }, { refreshToken: model.token },
{ {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
+2 -1
View File
@@ -8,6 +8,7 @@ import {
removeRefreshToken, removeRefreshToken,
} from "./func"; } from "./func";
import { refreshToken } from "./auth/refresh-token"; import { refreshToken } from "./auth/refresh-token";
import { API_BASE_URL } from "@/config/const";
declare global { declare global {
interface Window { interface Window {
@@ -16,7 +17,7 @@ declare global {
} }
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL, baseURL: API_BASE_URL,
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
+8 -19
View File
@@ -1,42 +1,31 @@
import { REFRESH_TOKEN_NAME, TOKEN_NAME } from "@/config/const";
export const getToken = async (): Promise<string | null> => { export const getToken = async (): Promise<string | null> => {
if (typeof window === "undefined") return null; if (typeof window === "undefined") return null;
return localStorage.getItem( return localStorage.getItem(TOKEN_NAME);
process.env.NEXT_PUBLIC_TOKEN_NAME as string
);
}; };
export const getRefreshToken = async (): Promise<string | null> => { export const getRefreshToken = async (): Promise<string | null> => {
if (typeof window === "undefined") return null; if (typeof window === "undefined") return null;
return localStorage.getItem( return localStorage.getItem(REFRESH_TOKEN_NAME);
process.env.NEXT_PUBLIC_REFRESH_TOKEN_NAME as string
);
}; };
export const setToken = async (token: string): Promise<void> => { export const setToken = async (token: string): Promise<void> => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
localStorage.setItem( localStorage.setItem(TOKEN_NAME, token);
process.env.NEXT_PUBLIC_TOKEN_NAME as string,
token
);
}; };
export const setRefreshToken = async (token: string): Promise<void> => { export const setRefreshToken = async (token: string): Promise<void> => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
localStorage.setItem( localStorage.setItem(REFRESH_TOKEN_NAME, token);
process.env.NEXT_PUBLIC_REFRESH_TOKEN_NAME as string,
token
);
}; };
export const removeToken = async (): Promise<void> => { export const removeToken = async (): Promise<void> => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
localStorage.removeItem(process.env.NEXT_PUBLIC_TOKEN_NAME as string); localStorage.removeItem(TOKEN_NAME);
}; };
export const removeRefreshToken = async (): Promise<void> => { export const removeRefreshToken = async (): Promise<void> => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
localStorage.removeItem( localStorage.removeItem(REFRESH_TOKEN_NAME);
process.env.NEXT_PUBLIC_REFRESH_TOKEN_NAME as string
);
}; };