fix inconsistency
This commit is contained in:
@@ -1,25 +1,37 @@
|
|||||||
import React from "react";
|
"use client";
|
||||||
import { Metadata } from "next";
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
import ChatList from "@/components/dashboard/ChatList";
|
import ChatList from "@/components/dashboard/ChatList";
|
||||||
import Dashboard from "@/components/dashboard/dashboard";
|
import Dashboard from "@/components/dashboard/dashboard";
|
||||||
|
import { MessageCircle } from "lucide-react";
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Customer Chats",
|
|
||||||
description: "Manage conversations with your customers",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ChatsPage() {
|
export default function ChatsPage() {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const authToken = document.cookie
|
||||||
|
.split("; ")
|
||||||
|
.find((row) => row.startsWith("Authorization="))
|
||||||
|
?.split("=")[1];
|
||||||
|
|
||||||
|
if (!authToken) {
|
||||||
|
router.push("/login");
|
||||||
|
}
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dashboard>
|
<Dashboard>
|
||||||
<div className="container mx-auto py-6 space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h1 className="text-3xl font-bold tracking-tight">Customer Chats</h1>
|
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white flex items-center">
|
||||||
|
<MessageCircle className="mr-2 h-6 w-6" />
|
||||||
|
Customer Chats
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-6">
|
|
||||||
<ChatList />
|
<ChatList />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</Dashboard>
|
</Dashboard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,33 @@
|
|||||||
|
|
||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import {
|
||||||
|
Plus,
|
||||||
|
MessageCircle,
|
||||||
|
Loader2,
|
||||||
|
RefreshCw,
|
||||||
|
ChevronLeft,
|
||||||
|
ChevronRight
|
||||||
|
} from "lucide-react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { getCookie } from "@/lib/client-utils";
|
import { getCookie } from "@/lib/client-utils";
|
||||||
@@ -260,91 +282,127 @@ export default function ChatList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="w-full">
|
<div className="space-y-4">
|
||||||
<CardHeader>
|
<div className="flex justify-between items-center">
|
||||||
<CardTitle className="flex justify-between items-center">
|
<div className="flex items-center space-x-4">
|
||||||
<span>Customer Chats</span>
|
<Select
|
||||||
<Button onClick={handleCreateChat}>New Chat</Button>
|
value={selectedStore || "all"}
|
||||||
</CardTitle>
|
onValueChange={(value) => setSelectedStore(value)}
|
||||||
{vendorStores.length === 0 ? (
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
No store available. Please create a store first.
|
|
||||||
</div>
|
|
||||||
) : vendorStores.length === 1 ? (
|
|
||||||
<div className="text-sm font-medium">
|
|
||||||
{vendorStores[0].name}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<label htmlFor="store-select" className="text-sm font-medium">
|
|
||||||
Store:
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
id="store-select"
|
|
||||||
value={selectedStore}
|
|
||||||
onChange={handleStoreChange}
|
|
||||||
className="rounded-md border border-input bg-background px-3 py-2 text-sm"
|
|
||||||
>
|
>
|
||||||
|
<SelectTrigger className="w-48">
|
||||||
|
<SelectValue placeholder="All Stores" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="all">All Stores</SelectItem>
|
||||||
{vendorStores.map((store) => (
|
{vendorStores.map((store) => (
|
||||||
<option key={store._id} value={store._id}>
|
<SelectItem key={store._id} value={store._id}>
|
||||||
{store.name}
|
{store.name}
|
||||||
</option>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</select>
|
</SelectContent>
|
||||||
</div>
|
</Select>
|
||||||
)}
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
{chats.length === 0 ? (
|
|
||||||
<div className="text-center py-12 px-4">
|
|
||||||
<div className="mb-4 mx-auto w-16 h-16 rounded-full bg-muted flex items-center justify-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-muted-foreground">
|
|
||||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h3 className="text-lg font-medium">No chats available</h3>
|
|
||||||
<p className="text-muted-foreground mt-2 mb-4">
|
|
||||||
There are no customer conversations for this store yet.
|
|
||||||
</p>
|
|
||||||
<Button
|
<Button
|
||||||
variant="default"
|
variant="outline"
|
||||||
onClick={handleCreateChat}
|
size="sm"
|
||||||
className="mt-2"
|
onClick={() => fetchChats()}
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
Start a new conversation
|
{loading ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCw className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
<span className="ml-2">Refresh</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Button onClick={handleCreateChat} size="sm">
|
||||||
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
|
New Chat
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="rounded-md border">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[200px]">Customer</TableHead>
|
||||||
|
<TableHead>Last Activity</TableHead>
|
||||||
|
<TableHead>Status</TableHead>
|
||||||
|
<TableHead className="text-right">Actions</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{loading ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4} className="h-24 text-center">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin mx-auto" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : chats.length === 0 ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={4} className="h-24 text-center">
|
||||||
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<MessageCircle className="h-8 w-8 text-muted-foreground mb-2" />
|
||||||
|
<p className="text-muted-foreground">No chats found</p>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
chats.map((chat) => (
|
||||||
{chats.map((chat) => (
|
<TableRow
|
||||||
<div
|
|
||||||
key={chat._id}
|
key={chat._id}
|
||||||
className="flex items-center justify-between p-4 rounded-lg border cursor-pointer hover:bg-muted/50 transition-colors"
|
className="cursor-pointer hover:bg-muted/50"
|
||||||
onClick={() => handleChatClick(chat._id)}
|
onClick={() => handleChatClick(chat._id)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-4">
|
<TableCell>
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
<Avatar>
|
<Avatar>
|
||||||
<AvatarFallback>
|
<AvatarFallback>
|
||||||
{chat.buyerId.slice(0, 2).toUpperCase()}
|
{chat.buyerId?.slice(0, 2).toUpperCase() || 'CU'}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium">Customer {chat.buyerId.slice(-4)}</h4>
|
<div className="font-medium">Customer {chat.buyerId.slice(0, 4)}</div>
|
||||||
<p className="text-sm text-muted-foreground">
|
{chat.orderId && (
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
Order #{chat.orderId}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
{formatDistanceToNow(new Date(chat.lastUpdated), { addSuffix: true })}
|
{formatDistanceToNow(new Date(chat.lastUpdated), { addSuffix: true })}
|
||||||
</p>
|
</TableCell>
|
||||||
</div>
|
<TableCell>
|
||||||
</div>
|
{unreadCounts.chatCounts[chat._id] > 0 ? (
|
||||||
{unreadCounts.chatCounts[chat._id] > 0 && (
|
<Badge variant="destructive" className="ml-1">
|
||||||
<Badge variant="destructive">
|
{unreadCounts.chatCounts[chat._id]} new
|
||||||
{unreadCounts.chatCounts[chat._id]} unread
|
|
||||||
</Badge>
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline">Read</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</TableCell>
|
||||||
))}
|
<TableCell className="text-right">
|
||||||
</div>
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleChatClick(chat._id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</TableBody>
|
||||||
</Card>
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user