Add CSV export for orders and update UI symbols
Introduces an exportOrdersToCSV function in lib/api-client.ts to allow exporting orders by status as a CSV file. Updates various UI components to use the '•' (bullet) symbol instead of '·' (middle dot) and replaces some emoji/unicode characters for improved consistency and compatibility. Also normalizes the 'use client' directive to include a BOM in many files.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { Package, ShoppingBag, Info, ExternalLink, Loader2, AlertTriangle } from "lucide-react";
|
||||
@@ -237,7 +237,7 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
||||
<div className="p-3 border-b">
|
||||
<h4 className="font-medium text-sm">Customer Orders</h4>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{orders.length} {orders.length === 1 ? 'order' : 'orders'} • Total: {formatPrice(
|
||||
{orders.length} {orders.length === 1 ? 'order' : 'orders'} ÔÇó Total: {formatPrice(
|
||||
orders.reduce((sum, order) => sum + order.totalPrice, 0)
|
||||
)}
|
||||
</p>
|
||||
@@ -279,11 +279,11 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
||||
<div className="flex justify-between items-center text-xs text-muted-foreground pl-5">
|
||||
<div className="flex gap-1">
|
||||
<span>{order.products.length} {order.products.length === 1 ? 'product' : 'products'}</span>
|
||||
<span>·</span>
|
||||
<span>•</span>
|
||||
<span>{formatPrice(order.totalPrice)}</span>
|
||||
{isOrderUnderpaid(order) && (
|
||||
<>
|
||||
<span>·</span>
|
||||
<span>•</span>
|
||||
<span className="text-red-500">Underpaid</span>
|
||||
</>
|
||||
)}
|
||||
@@ -299,4 +299,4 @@ export default function BuyerOrderInfo({ buyerId, chatId }: BuyerOrderInfoProps)
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -832,4 +832,4 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -420,4 +420,4 @@ export default function ChatTable() {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
@@ -350,4 +350,4 @@ export default function NewChatForm() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import OrderStats from "./order-stats"
|
||||
@@ -75,7 +75,7 @@ export default function Content({ username, orderStats }: ContentProps) {
|
||||
{greeting}, {username}!
|
||||
</h1>
|
||||
<p className="text-muted-foreground mt-1 italic text-sm">
|
||||
"{randomQuote.text}" — <span className="font-medium">{randomQuote.author}</span>
|
||||
"{randomQuote.text}" ÔÇö <span className="font-medium">{randomQuote.author}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type React from "react"
|
||||
import type React from "react"
|
||||
import Layout from "../layout/layout"
|
||||
|
||||
export default function Dashboard({ children }: { children: React.ReactNode }) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LucideIcon } from "lucide-react"
|
||||
import type { LucideIcon } from "lucide-react"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
|
||||
interface OrderStatsProps {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Card } from "@/components/ui/card";
|
||||
@@ -113,4 +113,4 @@ export default function PageLoading({
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { z } from 'zod';
|
||||
@@ -464,4 +464,4 @@ export default function EditPromotionForm({ promotion, onSuccess, onCancel }: Ed
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { z } from 'zod';
|
||||
@@ -459,4 +459,4 @@ export default function NewPromotionForm({ onSuccess, onCancel }: NewPromotionFo
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { Check, ChevronDown, X, Search } from 'lucide-react';
|
||||
@@ -248,4 +248,4 @@ export default function ProductSelector({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
@@ -222,7 +222,7 @@ export default function PromotionDetailsModal({
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-sm font-medium">Current Usage</span>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{promotion.usageCount} / {promotion.maxUsage || '∞'}
|
||||
{promotion.usageCount} / {promotion.maxUsage || 'Ôê×'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full bg-gray-200 rounded-full h-2">
|
||||
@@ -382,4 +382,4 @@ export default function PromotionDetailsModal({
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Plus, Tag, RefreshCw, Trash, Edit, Check, X, Eye } from 'lucide-react';
|
||||
@@ -184,7 +184,7 @@ export default function PromotionsList() {
|
||||
: 'None'}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{promotion.usageCount} / {promotion.maxUsage || '∞'}
|
||||
{promotion.usageCount} / {promotion.maxUsage || 'Ôê×'}
|
||||
</TableCell>
|
||||
<TableCell>{formatDate(promotion.endDate)}</TableCell>
|
||||
<TableCell>
|
||||
@@ -306,4 +306,4 @@ export default function PromotionsList() {
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
@@ -59,4 +59,4 @@ export default function PromotionsPageSkeleton() {
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user