Skip to content

Automated PR to merge dev to main #414

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "إضافة",
"UNPICK_LABEL": "إزالة"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "تم تقديم الطلب بنجاح",
"ORDER_FAILED_MESSAGE": "فشل في تقديم الطلب الجديد"
},
"REVIEWS": {
"REVIEWS_HEADER": "التقييمات",
Expand Down
4 changes: 3 additions & 1 deletion messages/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Pick",
"UNPICK_LABEL": "Unpick"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Order placed successfully",
"ORDER_FAILED_MESSAGE": "Failed to place new order"
},
"REVIEWS": {
"REVIEWS_HEADER": "Reviews",
Expand Down
4 changes: 3 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Pick",
"UNPICK_LABEL": "Unpick"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Order placed successfully",
"ORDER_FAILED_MESSAGE": "Failed to place new order"
},
"REVIEWS": {
"REVIEWS_HEADER": "Reviews",
Expand Down
4 changes: 3 additions & 1 deletion messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Agregar",
"UNPICK_LABEL": "Eliminar"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Pedido realizado con éxito",
"ORDER_FAILED_MESSAGE": "No se pudo realizar el nuevo pedido"
},
"REVIEWS": {
"REVIEWS_HEADER": "Reseñas",
Expand Down
4 changes: 3 additions & 1 deletion messages/ewe-BJ.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Tutu",
"UNPICK_LABEL": "Dzi"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Wòɖo ɖɔɖɔ laɖoɖo",
"ORDER_FAILED_MESSAGE": "Ɖe wòɖo ɖɔɖɔ laɖoɖo fofó me nyɛ"
},
"REVIEWS": {
"REVIEWS_HEADER": "Totoɖemewo",
Expand Down
4 changes: 3 additions & 1 deletion messages/fon-BJ.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Tɔn",
"UNPICK_LABEL": "Zàn"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Wɛ ɖe wɛ̀ nɔ̀",
"ORDER_FAILED_MESSAGE": "Kàkà wɛ̀ ɖe wɛ̀ nɔ̀ tuntun"
},
"REVIEWS": {
"REVIEWS_HEADER": "Kpondewu",
Expand Down
4 changes: 3 additions & 1 deletion messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Ajouter",
"UNPICK_LABEL": "Retirer"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Commande passée avec succès",
"ORDER_FAILED_MESSAGE": "Échec de la passation de la nouvelle commande"
},
"REVIEWS": {
"REVIEWS_HEADER": "Avis",
Expand Down
4 changes: 3 additions & 1 deletion messages/hau-NG.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Kara",
"UNPICK_LABEL": "Cire"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "An yi oda cikin nasara",
"ORDER_FAILED_MESSAGE": "Gaza yin sabon oda"
},
"REVIEWS": {
"REVIEWS_HEADER": "Bita",
Expand Down
4 changes: 3 additions & 1 deletion messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "追加",
"UNPICK_LABEL": "削除"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "注文が正常に完了しました",
"ORDER_FAILED_MESSAGE": "新しい注文に失敗しました"
},
"REVIEWS": {
"REVIEWS_HEADER": "レビュー",
Expand Down
4 changes: 3 additions & 1 deletion messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "추가",
"UNPICK_LABEL": "제거"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "주문이 성공적으로 완료되었습니다",
"ORDER_FAILED_MESSAGE": "새 주문을 실패했습니다"
},
"REVIEWS": {
"REVIEWS_HEADER": "리뷰",
Expand Down
4 changes: 3 additions & 1 deletion messages/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Thêm",
"UNPICK_LABEL": "Gỡ bỏ"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "Đặt hàng thành công",
"ORDER_FAILED_MESSAGE": "Không thể đặt đơn hàng mới"
},
"REVIEWS": {
"REVIEWS_HEADER": "Đánh giá",
Expand Down
4 changes: 3 additions & 1 deletion messages/yor-NG.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "Fi kun",
"UNPICK_LABEL": "Yọ"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "A ti fiṣẹṣẹ ránṣẹ̀",
"ORDER_FAILED_MESSAGE": "Ìfiṣẹṣẹ tuntun kò ṣàṣeyọrí"
},
"REVIEWS": {
"REVIEWS_HEADER": "Atunyẹwo",
Expand Down
4 changes: 3 additions & 1 deletion messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "添加",
"UNPICK_LABEL": "移除"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "订单提交成功",
"ORDER_FAILED_MESSAGE": "提交新订单失败"
},
"REVIEWS": {
"REVIEWS_HEADER": "评论",
Expand Down
4 changes: 3 additions & 1 deletion messages/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@
"PICK_LABEL": "新增",
"UNPICK_LABEL": "移除"
}
}
},
"ORDER_SUCCESSFUL_MESSAGE": "訂單提交成功",
"ORDER_FAILED_MESSAGE": "提交新訂單失敗"
},
"REVIEWS": {
"REVIEWS_HEADER": "評論",
Expand Down
85 changes: 50 additions & 35 deletions src/app/[locale]/seller/sale-items/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ import Link from 'next/link';

import React, { useEffect, useState, useContext, useRef } from 'react';

import ConfirmDialog from '@/components/shared/confirm';
import ConfirmDialog, { Notification } from '@/components/shared/confirm';
import { Button, OutlineBtn } from '@/components/shared/Forms/Buttons/Buttons';
import { Select, TextArea } from '@/components/shared/Forms/Inputs/Inputs';
import MembershipIcon from '@/components/shared/membership/MembershipIcon';
import TrustMeter from '@/components/shared/Review/TrustMeter';
import { ListItem } from '@/components/shared/Seller/ShopItem';
import ToggleCollapse from '@/components/shared/Seller/ToggleCollapse';
import Skeleton from '@/components/skeleton/skeleton';
import { payWithPi } from '@/config/payment';
import {
ISeller,
IUserSettings,
IUser,
SellerItem,
PaymentDataType,
PaymentType,
StockLevelType
SellerItem,
StockLevelType,
OrderStatusType,
PickedItems
} from '@/constants/types';
import { createAndUpdateOrder } from '@/services/orderApi';
import { fetchSellerItems, fetchSingleSeller } from '@/services/sellerApi';
import { fetchSingleUserSettings } from '@/services/userSettingsApi';
import { fetchToggle } from '@/services/toggleApi';
Expand All @@ -35,14 +35,14 @@ import {

import { AppContext } from '../../../../../../context/AppContextProvider';
import logger from '../../../../../../logger.config.mjs';
import axiosClient from "@/config/client";

export default function BuyFromSellerForm({ params }: { params: { id: string } }) {
const SUBHEADER = "font-bold mb-2";
const t = useTranslations();
const locale = useLocale();
const sellerId = params.id;


const { currentUser, autoLoginUser, reload, setReload, showAlert } = useContext(AppContext);
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [linkUrl, setLinkUrl] = useState('');
const [sellerShopInfo, setSellerShopInfo] = useState<ISeller | null>(null);
Expand All @@ -53,9 +53,11 @@ export default function BuyFromSellerForm({ params }: { params: { id: string } }
const [buyerDescription, setBuyerDescription] = useState<string>("");
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const { currentUser, autoLoginUser, reload, setReload, showAlert } = useContext(AppContext);
const [pickedItems, setPickedItems] = useState<{ itemId: string; quantity: number }[]>([]);

const [pickedItems, setPickedItems] = useState<PickedItems[]>([]);
const [isOnlineShoppingEnabled, setOnlineShoppingEnabled] = useState(false);
const [showCheckoutStatus, setShowCheckoutStatus] = useState(false);
const [checkoutStatusMessage, setCheckoutStatusMessage] = useState<string>("")

const observer = useRef<IntersectionObserver | null>(null);

Expand Down Expand Up @@ -135,42 +137,49 @@ export default function BuyFromSellerForm({ params }: { params: { id: string } }
getSellerItems();
}, [sellerShopInfo, reload]);

const onPaymentComplete = (data:any) => {
logger.info('Payment completed successfully:', data.message);
showAlert('Payment completed successfully');
const onOrderComplete = (data:any) => {
logger.info('Order placed successfully:', data.message);
showAlert('Order placed successfully');
setCheckoutStatusMessage(t('SCREEN.BUY_FROM_SELLER.ORDER_SUCCESSFUL_MESSAGE'))
setShowCheckoutStatus(true);
setPickedItems([]);
setReload(true);
setTotalAmount(0);
setBuyerDescription("");
}

const onPaymentError = (error: Error) => {
logger.error('Error completing payment:', error);
showAlert('Error completing payment: ' + error.message);
setReload(true);
const onOrderError = (error: Error) => {
logger.error("Error creating new order", error.message);
setCheckoutStatusMessage(t('SCREEN.BUY_FROM_SELLER.ORDER_FAILED_MESSAGE'))
setShowCheckoutStatus(true);
}

const checkoutOrder = async () => {
if (!currentUser?.pi_uid) return setError('User not logged in for payment');
if (!currentUser?.pi_uid) {
return setError('User not logged in for payment');
}

const paymentData: PaymentDataType = {
amount: totalAmount,
memo: `Map of Pi payment from ${currentUser.pi_username} to ${sellerInfo?.pi_username}`,
metadata: {
payment_type: PaymentType.BuyerCheckout,
OrderPayment: {
items: pickedItems,
buyer: currentUser.pi_uid,
seller: sellerId,
fulfillment_method: sellerShopInfo?.fulfillment_method,
seller_fulfillment_description: sellerShopInfo?.fulfillment_description,
buyer_fulfillment_description: buyerDescription,
}
},
const newOrderData = {
buyerId: currentUser.pi_uid,
sellerId: sellerId,
paymentId: null,
totalAmount: totalAmount,
status: OrderStatusType.Pending,
fulfillmentMethod: sellerShopInfo?.fulfillment_method,
sellerFulfillmentDescription: sellerShopInfo?.fulfillment_description,
buyerFulfillmentDescription: buyerDescription,
};
await payWithPi(paymentData, onPaymentComplete, onPaymentError);
setPickedItems([]);
}

try {
const newOrder = await createAndUpdateOrder(newOrderData, pickedItems);
if (newOrder && newOrder._id) {
onOrderComplete(newOrder)
setPickedItems([]);
}
} catch (error:any) {
onOrderError(error);
}
}

// loading condition
if (loading) {
Expand Down Expand Up @@ -276,6 +285,7 @@ export default function BuyFromSellerForm({ params }: { params: { id: string } }
/>
))
}

</div>
<div>
<h2 className={SUBHEADER}>{t('SCREEN.SELLER_REGISTRATION.FULFILLMENT_METHOD_TYPE.FULFILLMENT_METHOD_TYPE_LABEL')}</h2>
Expand Down Expand Up @@ -350,6 +360,11 @@ export default function BuyFromSellerForm({ params }: { params: { id: string } }
message={t('SHARED.CONFIRM_DIALOG')}
url={linkUrl}
/>

{showCheckoutStatus && <div className='fixed inset-0 flex items-center justify-center'>
<Notification message={checkoutStatusMessage} showDialog={showCheckoutStatus} setShowDialog={setShowCheckoutStatus} />
</div>}

</div>
)}
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/components/shared/Seller/ShopItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,11 @@ export const ListItem: React.FC<{

const [quantity, setQuantity] = useState<number>(1)

// Reset quantity when item changes
useEffect(() => {
setQuantity(1);
}, [item]);

const handlePicked = (itemId: string, price: number): void => {
setPickedItems((prev) => {
const existingItem = prev.find((item) => item.itemId === itemId);
Expand Down
19 changes: 10 additions & 9 deletions src/services/orderApi.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import axiosClient from "@/config/client";
import { PickedItems } from "@/constants/types";
import logger from '../../logger.config.mjs';

// Create or Update an Order
export const createOrUpdateOrder = async (orderData: any) => {
// Create and update an Order
export const createAndUpdateOrder = async (orderData: any, orderItems: PickedItems[]) => {
try {
logger.info("Sending request to create or update order", { orderData });
const response = await axiosClient.post("/orders", orderData);
if (response.status === 201) {
logger.info(`Order processed successfully with Status ${response.status}`, {
logger.info("Sending request to create and update order", { orderData });
const response = await axiosClient.post("/orders", { orderData, orderItems });
if (response.status === 200) {
logger.info(`Order created and updated successfully with Status ${response.status}`, {
data: response.data,
});
return response.data;
} else {
logger.error(`Order processing failed with Status ${response.status}`);
logger.error(`Order creation and update failed with Status ${response.status}`);
return null;
}
} catch (error) {
logger.error("Error processing order:", error);
throw new Error("Failed to create or update order. Please try again later.");
logger.error('Creating and updating order encountered an error:', error);
throw new Error('Failed to create and update order. Please try again later.');
}
};

Expand Down