From 5e1afc5ccc9a687197a917809c5f7f6e476f0bf4 Mon Sep 17 00:00:00 2001 From: Nagarajan Date: Thu, 30 Apr 2026 10:54:14 +0530 Subject: [PATCH] Call history, Clear chat --- src/components/chat/CallHistory.jsx | 254 +++++++++++ .../profiledetail/MatrimonyProfile.jsx | 395 +++++++++--------- src/pages/ChatPage.jsx | 176 +++++--- src/services/chatApi.js | 42 ++ 4 files changed, 606 insertions(+), 261 deletions(-) create mode 100644 src/components/chat/CallHistory.jsx diff --git a/src/components/chat/CallHistory.jsx b/src/components/chat/CallHistory.jsx new file mode 100644 index 0000000..b1493bc --- /dev/null +++ b/src/components/chat/CallHistory.jsx @@ -0,0 +1,254 @@ +import React, { useState, useEffect } from 'react'; +import { ArrowLeft, MoreVertical, Loader2 } from 'lucide-react'; +import { getCallHistoryMyList, getCallHistoryOthersList, deleteCallHistory } from '../../services/chatApi'; +import toast from 'react-hot-toast'; +import { useQuery } from '@tanstack/react-query'; +import { getHeaderDetails } from '../../api/preview.api'; + +const CallHistory = ({ onBack }) => { + const [activeTab, setActiveTab] = useState('me'); + const [historyList, setHistoryList] = useState([]); + const [loading, setLoading] = useState(true); + + const { data: headerData } = useQuery({ + queryKey: ["headerDetails"], + queryFn: getHeaderDetails, + }); + // console.log("headerData", headerData); + + const myDetails = headerData?.myDetails || {}; + + const [isEditMode, setIsEditMode] = useState(false); + const [selectedIds, setSelectedIds] = useState([]); + const [showMenu, setShowMenu] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + + const fetchData = async () => { + setLoading(true); + setHistoryList([]); + try { + let res; + if (activeTab === 'me') { + res = await getCallHistoryMyList(); + } else { + res = await getCallHistoryOthersList(); + } + + const data = res?.call_list || res?.data || res || []; + setHistoryList(Array.isArray(data) ? data : []); + } catch (error) { + toast.error("Failed to load call history."); + setHistoryList([]); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + setIsEditMode(false); + setSelectedIds([]); + }, [activeTab]); + + const toggleSelection = (id) => { + if (selectedIds.includes(id)) { + setSelectedIds(selectedIds.filter(item => item !== id)); + } else { + setSelectedIds([...selectedIds, id]); + } + }; + + const handleDelete = async () => { + if (selectedIds.length === 0) return; + + setIsDeleting(true); + try { + const res = await deleteCallHistory(selectedIds); + toast.success(res?.message || "History deleted successfully."); + setIsEditMode(false); + setSelectedIds([]); + fetchData(); + } catch (error) { + toast.error("Failed to delete history."); + } finally { + setIsDeleting(false); + } + }; + + const getSkeletons = () => { + return Array(5).fill(0).map((_, idx) => ( +
+
+
+
+
+
+
+ )); + }; + + return ( +
+ {/* Header */} +
+
+ +

Call History

+
+ +
+ + + {showMenu && ( +
+ +
+ )} +
+
+ + {/* User Info Banner */} +
+
+ Profile +
+
+
+

{myDetails.name || "User"}

+ {myDetails.is_paid && ( + Free // Or Paid dynamically + )} +
+

+ ID : {myDetails.member_id || myDetails.profile_id || "N/A"} +

+
+
+ + {/* Tabs */} +
+ + +
+ + {/* Content List */} +
+ {loading ? ( + getSkeletons() + ) : historyList.length === 0 ? ( +
+
+ + + +
+

No Call History found

+
+ ) : ( +
+ {historyList.map((item, idx) => ( +
isEditMode && toggleSelection(item.id)} + className={`flex items-center gap-4 p-4 transition-colors cursor-pointer hover:bg-gray-50 ${isEditMode && selectedIds.includes(item.id) ? 'bg-red-50/50' : 'bg-white'}`} + > + {/* Checkbox for Edit Mode */} + {isEditMode && ( +
+
+ {selectedIds.includes(item.id) && ( + + )} +
+
+ )} + + {/* Avatar */} + {item.name} + + {/* Details */} +
+
+

{item.name}

+ {item.date || item.created_at || "N/A"} +
+ + {item.mobile ? ( +

+ Mobile No : {item.mobile} +

+ ) : ( +

+ ID : {item.member_id || "N/A"} +

+ )} +
+
+ ))} +
+ )} +
+ + {/* Delete Button (Sticky Bottom) */} + {isEditMode && selectedIds.length > 0 && ( +
+ +
+ )} +
+ ); +}; + +export default CallHistory; diff --git a/src/components/profiledetail/MatrimonyProfile.jsx b/src/components/profiledetail/MatrimonyProfile.jsx index fb4c557..89c7c68 100644 --- a/src/components/profiledetail/MatrimonyProfile.jsx +++ b/src/components/profiledetail/MatrimonyProfile.jsx @@ -54,8 +54,8 @@ const MatrimonyProfile = ({ data, onRefresh }) => { const education = data.educationalDetails; const lifestyle = data.lifestyleDetails; - const profileImages = personal.images && personal.images.length > 0 - ? personal.images + const profileImages = personal.images && personal.images.length > 0 + ? personal.images : [profile.profile_picture || "https://www.thirukalyanam.amrithaa.net/backend/app-assets/images/portrait/small/no-image.png"]; const [isUpgradeModalOpen, setIsUpgradeModalOpen] = useState(false); @@ -235,10 +235,10 @@ const MatrimonyProfile = ({ data, onRefresh }) => { const handleMessage = (e) => { if (e) e.stopPropagation(); - + if (profile.chat_id) { - navigate(`/chat/${profile.chat_id}`); - return; + navigate(`/chat/${profile.chat_id}`); + return; } if (!isUserPaid) { @@ -267,16 +267,16 @@ const MatrimonyProfile = ({ data, onRefresh }) => { const _handleCreateChat = async () => { if (isCreatingChat) return; - + setIsChatConfirmModalOpen(false); setIsCreatingChat(true); - + try { const response = await axiosInstance.post(API_ENDPOINTS.CHAT_CREATE, { profile_id: profile.id }); if (response.data?.status === true || response.data?.status === 'success') { const newChatId = response.data?.chat_id; - + try { await sendMessage(newChatId, "This profile has initiated a chat with you"); } catch (msgErr) { @@ -358,9 +358,9 @@ const MatrimonyProfile = ({ data, onRefresh }) => { if (!value) return "N/A"; const strValue = String(value); const isUpgrade = strValue.toLowerCase().includes("upgrade"); - + return ( - isUpgrade && setIsUpgradeModalOpen(true)} > @@ -378,11 +378,11 @@ const MatrimonyProfile = ({ data, onRefresh }) => { return (
- setReportModalOpen(false)} - onSubmit={handleReportAction} - actionType={reportActionType} + setReportModalOpen(false)} + onSubmit={handleReportAction} + actionType={reportActionType} />
- - - -
{/* Action Buttons */}
- {profile.is_blocked ? ( - - ) : profile.is_send_interest_received && profile.statusReceived?.toLowerCase() === 'pending' ? ( + {profile.is_send_interest_received && profile.statusReceived?.toLowerCase() === 'pending' ? ( <> - - ) : (!profile.is_send_interest && !profile.is_send_interest_received) ? ( - ) : ( <> - -
)} - +
{/* Personal Information Section */}
@@ -1056,162 +1049,160 @@ const MatrimonyProfile = ({ data, onRefresh }) => {
-
-
-
- -
-

Contact Details

+
+
+
+
+

Contact Details

+
-
-
- Phone Number - : - +
+ Phone Number + : + _handleContactInteraction('mobile')} - > - {unlockedMobile || profile.mobile || "N/A"} - -
-
- Email - : - _handleContactInteraction('mobile')} + > + {unlockedMobile || profile.mobile || "N/A"} + +
+
+ Email + : + _handleContactInteraction('email')} - > - {unlockedEmail || profile.email || "N/A"} - -
+ onClick={() => _handleContactInteraction('email')} + > + {unlockedEmail || profile.email || "N/A"} +
+
- {/* Educational & Professional Section */} -
-
-
- -
-

Educational & Professional

-
- -
- {(education.education || safeVal(profile.education, 'education_name')) && ( -
- Highest Qualification - : - {_renderValue(education.education || safeVal(profile.education, 'education_name'))} -
- )} - {(education.study_field || safeVal(profile.study_field, 'study_field_name')) && ( -
- Field of Study - : - {_renderValue(education.study_field || safeVal(profile.study_field, 'study_field_name'))} -
- )} - {(profile.college_name || education.college_name) && ( -
- College Name - : - {_renderValue(profile.college_name || education.college_name)} -
- )} - {(education.employee_type || safeVal(profile.employee_type, 'employee_type_name')) && ( -
- Employee type - : - {_renderValue(education.employee_type || safeVal(profile.employee_type, 'employee_type_name'))} -
- )} - {(education.occupation || safeVal(profile.occupation, 'occupation_name')) && ( -
- Occupation - : - {_renderValue(education.occupation || safeVal(profile.occupation, 'occupation_name'))} -
- )} - {profile.occupation_details && ( -
- Occupation Details - : - {profile.occupation_details} -
- )} - {(education.company_name || profile.company_name) && ( -
- Organization Name - : - {_renderValue(education.company_name || profile.company_name)} -
- )} - {(profile.income_currency || education.income_currency) && ( -
- Income Currency Type - : - {_renderValue(profile.income_currency || education.income_currency)} -
- )} - {(education.annual_income || safeVal(profile.annual_income, 'annual_income_name')) && ( -
- Annual Income - : - {_renderValue(education.annual_income || safeVal(profile.annual_income, 'annual_income_name'))} -
- )} + {/* Educational & Professional Section */} +
+
+
+
+

Educational & Professional

- {/* Work Location Section */} -
-
-
- +
+ {(education.education || safeVal(profile.education, 'education_name')) && ( +
+ Highest Qualification + : + {_renderValue(education.education || safeVal(profile.education, 'education_name'))}
-

Work Location

-
- -
- {(education.work_country_name || profile.work_country_name) && ( -
- Country - : - {education.work_country_name || profile.work_country_name} -
- )} - {(education.work_state_name || profile.work_state_name) && ( -
- State - : - {education.work_state_name || profile.work_state_name} -
- )} - {(education.work_city || education.work_district_name || profile.work_city || profile.work_district_name) && ( -
- City - : - {education.work_city || education.work_district_name || profile.work_city || profile.work_district_name} -
- )} - {(education.work_location || profile.work_location) && ( -
- Address - : - {education.work_location || profile.work_location} -
- )} -
+ )} + {(education.study_field || safeVal(profile.study_field, 'study_field_name')) && ( +
+ Field of Study + : + {_renderValue(education.study_field || safeVal(profile.study_field, 'study_field_name'))} +
+ )} + {(profile.college_name || education.college_name) && ( +
+ College Name + : + {_renderValue(profile.college_name || education.college_name)} +
+ )} + {(education.employee_type || safeVal(profile.employee_type, 'employee_type_name')) && ( +
+ Employee type + : + {_renderValue(education.employee_type || safeVal(profile.employee_type, 'employee_type_name'))} +
+ )} + {(education.occupation || safeVal(profile.occupation, 'occupation_name')) && ( +
+ Occupation + : + {_renderValue(education.occupation || safeVal(profile.occupation, 'occupation_name'))} +
+ )} + {profile.occupation_details && ( +
+ Occupation Details + : + {profile.occupation_details} +
+ )} + {(education.company_name || profile.company_name) && ( +
+ Organization Name + : + {_renderValue(education.company_name || profile.company_name)} +
+ )} + {(profile.income_currency || education.income_currency) && ( +
+ Income Currency Type + : + {_renderValue(profile.income_currency || education.income_currency)} +
+ )} + {(education.annual_income || safeVal(profile.annual_income, 'annual_income_name')) && ( +
+ Annual Income + : + {_renderValue(education.annual_income || safeVal(profile.annual_income, 'annual_income_name'))} +
+ )}
+
+ + {/* Work Location Section */} +
+
+
+ +
+

Work Location

+
+ +
+ {(education.work_country_name || profile.work_country_name) && ( +
+ Country + : + {education.work_country_name || profile.work_country_name} +
+ )} + {(education.work_state_name || profile.work_state_name) && ( +
+ State + : + {education.work_state_name || profile.work_state_name} +
+ )} + {(education.work_city || education.work_district_name || profile.work_city || profile.work_district_name) && ( +
+ City + : + {education.work_city || education.work_district_name || profile.work_city || profile.work_district_name} +
+ )} + {(education.work_location || profile.work_location) && ( +
+ Address + : + {education.work_location || profile.work_location} +
+ )} +
+
{/* Modals */} { {/* View Contact Confirmation Modal */} {isViewContactModalOpen && (
- -

Note

You need to view this profile's contact details. If you choose to "Proceed" one count will be deducted from your subscription.

- -

Success!

The contact details have been unlocked.

- +
{(() => { const mobile = unlockedMobile || (profile.mobile && !profile.mobile.toLowerCase().includes("view") ? profile.mobile : null); @@ -1369,7 +1360,7 @@ const MatrimonyProfile = ({ data, onRefresh }) => {
); })()} - + {(() => { const email = unlockedEmail || (profile.email && !profile.email.toLowerCase().includes("view") ? profile.email : null); if (!email) return null; @@ -1412,9 +1403,9 @@ const MatrimonyProfile = ({ data, onRefresh }) => { {isChatConfirmModalOpen && (() => { const currentMobile = unlockedMobile || profile.mobile || ""; const mobileLower = currentMobile.toLowerCase(); - const isMobileVisible = currentMobile !== "" && - !mobileLower.includes("upgrade") && - !mobileLower.includes("view contact"); + const isMobileVisible = currentMobile !== "" && + !mobileLower.includes("upgrade") && + !mobileLower.includes("view contact"); return (
@@ -1424,29 +1415,29 @@ const MatrimonyProfile = ({ data, onRefresh }) => { exit={{ opacity: 0, scale: 0.95 }} className="bg-white rounded-[32px] p-8 max-w-md w-full shadow-2xl text-center relative" > -

{isMobileVisible ? "Ready to Chat?" : "Note"}

- {isMobileVisible + {isMobileVisible ? <>Are you ready to chat with {currentMobile}? : <>Starting a conversation will use 1 chat count. Are you ready to proceed?}

- - - + {showMenu && (
- -
)}
- + {/* Search */}
@@ -425,11 +464,28 @@ const ChatUI = () => { contacts.map((contact, index) => (
handleChatSelect(contact.id)} - className={`flex items-center gap-3 p-4 cursor-pointer hover:bg-gray-50 border-b border-gray-100 ${ - selectedChat === contact.id ? 'bg-blue-50' : '' - }`} + onClick={() => { + if (isEditContactMode) { + toggleChatSelection(contact.id); + } else { + handleChatSelect(contact.id); + } + }} + className={`flex items-center gap-3 p-4 cursor-pointer hover:bg-gray-50 border-b border-gray-100 ${selectedChat === contact.id ? 'bg-blue-50' : '' + } ${isEditContactMode && selectedChats.includes(contact.id) ? 'bg-red-50/50' : ''}`} > + {isEditContactMode && ( +
+
+ {selectedChats.includes(contact.id) && ( + + )} +
+
+ )}
{ )) )}
+ {/* Delete Button for Chats */} + {isEditContactMode && selectedChats.length > 0 && ( +
+ +
+ )}
{/* Chat Area */} {selectedChat && !showCallHistory && ( -
+
{/* Chat Header */}
@@ -493,13 +560,13 @@ const ChatUI = () => {
- - + {showChatMenu && (
- @@ -525,7 +592,7 @@ const ChatUI = () => {
{/* Messages */} -
@@ -543,7 +610,7 @@ const ChatUI = () => { {hasMore && !loadingMore && chatMessages.length > 0 && (
- -
+
+
)}
diff --git a/src/services/chatApi.js b/src/services/chatApi.js index 3ad5878..0693a3d 100644 --- a/src/services/chatApi.js +++ b/src/services/chatApi.js @@ -32,3 +32,45 @@ export const sendMessage = async (chatId, message) => { throw error; } }; + +export const getCallHistoryMyList = async () => { + try { + const response = await axiosInstance.get(`call_my_list`); + return response.data; + } catch (error) { + console.error("Error fetching my call history:", error); + throw error; + } +}; + +export const getCallHistoryOthersList = async () => { + try { + const response = await axiosInstance.get(`call_others_list`); + return response.data; + } catch (error) { + console.error("Error fetching others call history:", error); + throw error; + } +}; + +export const deleteCallHistory = async (ids) => { + try { + const queryStr = ids.map((id, index) => `ids[${index}]=${id}`).join('&'); + const response = await axiosInstance.get(`call_list_delete?${queryStr}`); + return response.data; + } catch (error) { + console.error("Error deleting call history:", error); + throw error; + } +}; + +export const deleteChats = async (ids) => { + try { + const queryStr = ids.map((id, index) => `ids[${index}]=${id}`).join('&'); + const response = await axiosInstance.post(`chat/delete?${queryStr}`); + return response.data; + } catch (error) { + console.error("Error deleting chats:", error); + throw error; + } +};