added close chat option to chat

This commit is contained in:
Alex
2026-04-10 07:36:54 -06:00
parent 5850adedc3
commit 8fc6f4b8d1
9 changed files with 267 additions and 167 deletions

View File

@@ -2,13 +2,14 @@ package com.example.petstoremobile.api;
import com.example.petstoremobile.dtos.ConversationDTO; import com.example.petstoremobile.dtos.ConversationDTO;
import com.example.petstoremobile.dtos.MessageDTO; import com.example.petstoremobile.dtos.MessageDTO;
import com.example.petstoremobile.dtos.UpdateConversationStatusRequest;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.Body; import retrofit2.http.Body;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.POST; import retrofit2.http.PUT;
import retrofit2.http.Path; import retrofit2.http.Path;
//api calls to get conversations //api calls to get conversations
@@ -20,4 +21,7 @@ public interface ChatApi {
@GET("api/v1/chat/conversations/{conversationId}") @GET("api/v1/chat/conversations/{conversationId}")
Call<ConversationDTO> getConversationById(@Path("conversationId") Long conversationId); Call<ConversationDTO> getConversationById(@Path("conversationId") Long conversationId);
@PUT("api/v1/chat/conversations/{conversationId}")
Call<ConversationDTO> updateConversationStatus(@Path("conversationId") Long conversationId, @Body UpdateConversationStatusRequest request);
} }

View File

@@ -5,7 +5,7 @@ import java.math.BigDecimal;
public class CouponDTO { public class CouponDTO {
private Long couponId; private Long couponId;
private String couponCode; private String couponCode;
private String discountType; // FIXED, PERCENT private String discountType;
private BigDecimal discountValue; private BigDecimal discountValue;
private BigDecimal minOrderAmount; private BigDecimal minOrderAmount;
private Boolean active; private Boolean active;

View File

@@ -0,0 +1,17 @@
package com.example.petstoremobile.dtos;
public class UpdateConversationStatusRequest {
private String status;
public UpdateConversationStatusRequest(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@@ -127,6 +127,7 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
binding.btnAttach.setOnClickListener(v -> selectAttachment()); binding.btnAttach.setOnClickListener(v -> selectAttachment());
binding.btnRemoveAttachment.setOnClickListener(v -> removeAttachment()); binding.btnRemoveAttachment.setOnClickListener(v -> removeAttachment());
binding.btnCloseChat.setOnClickListener(v -> closeChat());
setupDrawerToggles(); setupDrawerToggles();
setupRecyclerViews(); setupRecyclerViews();
@@ -356,6 +357,30 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
viewModel.loadMessageHistory(activeConversationId); viewModel.loadMessageHistory(activeConversationId);
} }
private void closeChat() {
if (activeConversationId == null) return;
DialogUtils.showConfirmDialog(requireContext(), "Close Chat",
"Are you sure you want to close this chat? This will notify the customer.", () -> {
viewModel.sendMessage(activeConversationId, "The Chat has been closed").observe(getViewLifecycleOwner(), resource -> {
if (resource != null && resource.status == Resource.Status.SUCCESS) {
viewModel.addMessageLocally(resource.data);
viewModel.closeConversation(activeConversationId).observe(getViewLifecycleOwner(), statusResource -> {
if (statusResource == null) return;
setLoading(statusResource.status == Resource.Status.LOADING);
if (statusResource.status == Resource.Status.SUCCESS) {
viewModel.loadConversations();
setConversationActive(true, "CLOSED");
} else if (statusResource.status == Resource.Status.ERROR) {
Toast.makeText(requireContext(), "Failed to close chat: " + statusResource.message, Toast.LENGTH_SHORT).show();
}
});
}
});
});
}
private void sendMessage() { private void sendMessage() {
if (activeConversationId == null) return; if (activeConversationId == null) return;
String text = binding.etMessage.getText().toString().trim(); String text = binding.etMessage.getText().toString().trim();
@@ -489,6 +514,7 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
private void setConversationActive(boolean active, String status) { private void setConversationActive(boolean active, String status) {
boolean isClosed = "CLOSED".equalsIgnoreCase(status); boolean isClosed = "CLOSED".equalsIgnoreCase(status);
UIUtils.setViewsEnabled(active && !isClosed, binding.btnSend, binding.etMessage, binding.btnAttach); UIUtils.setViewsEnabled(active && !isClosed, binding.btnSend, binding.etMessage, binding.btnAttach);
binding.btnCloseChat.setVisibility(active && !isClosed ? View.VISIBLE : View.GONE);
if (!active) { if (!active) {
activeConversationId = null; activeConversationId = null;

View File

@@ -43,15 +43,13 @@ public class ListFragment extends Fragment {
// Check user role and restrict access for STAFF // Check user role and restrict access for STAFF
String role = tokenManager.getRole(); String role = tokenManager.getRole();
if ("STAFF".equalsIgnoreCase(role)) { if ("STAFF".equalsIgnoreCase(role)) {
binding.drawerSuppliers.setVisibility(View.GONE); binding.sectionAdmin.setVisibility(View.GONE);
binding.drawerInventory.setVisibility(View.GONE); } else if ("ADMIN".equalsIgnoreCase(role)) {
} binding.sectionAdmin.setVisibility(View.VISIBLE);
// Only show for ADMIN
if ("ADMIN".equalsIgnoreCase(role)) {
binding.drawerStaff.setVisibility(View.VISIBLE); binding.drawerStaff.setVisibility(View.VISIBLE);
} else { } else {
binding.drawerStaff.setVisibility(View.GONE); // Default or other roles
binding.sectionAdmin.setVisibility(View.GONE);
} }
//add Listeners to the drawer so user won't be able to interact with the innerContainer (the list fragments) //add Listeners to the drawer so user won't be able to interact with the innerContainer (the list fragments)

View File

@@ -10,6 +10,7 @@ import com.example.petstoremobile.dtos.CustomerDTO;
import com.example.petstoremobile.dtos.MessageDTO; import com.example.petstoremobile.dtos.MessageDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.SendMessageRequest; import com.example.petstoremobile.dtos.SendMessageRequest;
import com.example.petstoremobile.dtos.UpdateConversationStatusRequest;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import java.util.List; import java.util.List;
@@ -73,6 +74,13 @@ public class ChatRepository extends BaseRepository {
return executeCall(messageApi.downloadAttachment(messageId)); return executeCall(messageApi.downloadAttachment(messageId));
} }
/**
* Updates the status of a conversation (e.g., OPEN to CLOSED).
*/
public LiveData<Resource<ConversationDTO>> updateConversationStatus(Long conversationId, UpdateConversationStatusRequest request) {
return executeCall(chatApi.updateConversationStatus(conversationId, request));
}
/** /**
* Fetches a paginated list of customers. * Fetches a paginated list of customers.
*/ */

View File

@@ -9,6 +9,7 @@ import com.example.petstoremobile.dtos.CustomerDTO;
import com.example.petstoremobile.dtos.MessageDTO; import com.example.petstoremobile.dtos.MessageDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.SendMessageRequest; import com.example.petstoremobile.dtos.SendMessageRequest;
import com.example.petstoremobile.dtos.UpdateConversationStatusRequest;
import com.example.petstoremobile.models.Chat; import com.example.petstoremobile.models.Chat;
import com.example.petstoremobile.models.Message; import com.example.petstoremobile.models.Message;
import com.example.petstoremobile.repositories.ChatRepository; import com.example.petstoremobile.repositories.ChatRepository;
@@ -126,6 +127,10 @@ public class ChatListViewModel extends ViewModel {
return chatRepository.downloadAttachment(messageId); return chatRepository.downloadAttachment(messageId);
} }
public LiveData<Resource<ConversationDTO>> closeConversation(Long conversationId) {
return chatRepository.updateConversationStatus(conversationId, new UpdateConversationStatusRequest("CLOSED"));
}
public void addMessageLocally(MessageDTO dto) { public void addMessageLocally(MessageDTO dto) {
List<Message> current = new ArrayList<>(messageList.getValue()); List<Message> current = new ArrayList<>(messageList.getValue());
current.add(dtoToModel(dto)); current.add(dtoToModel(dto));

View File

@@ -34,8 +34,9 @@
<TextView <TextView
android:id="@+id/tvChatTitle" android:id="@+id/tvChatTitle"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Customer Chat" android:text="Customer Chat"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="20sp" android:textSize="20sp"
@@ -43,6 +44,16 @@
android:paddingStart="8dp" android:paddingStart="8dp"
android:paddingEnd="8dp"/> android:paddingEnd="8dp"/>
<Button
android:id="@+id/btnCloseChat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close Chat"
android:textSize="12sp"
android:backgroundTint="@color/accent_coral"
android:textColor="@color/white"
android:visibility="gone"/>
</LinearLayout> </LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView

View File

@@ -83,10 +83,91 @@
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="24dp"> android:paddingBottom="24dp">
<!-- BUSINESS SECTION -->
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="MANAGE" android:text="BUSINESS"
android:textColor="@color/text_light"
android:textSize="11sp"
android:letterSpacing="0.15"
android:paddingStart="16dp"
android:paddingTop="24dp"
android:paddingBottom="8dp"/>
<LinearLayout
android:id="@+id/drawerAnalytics"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Analytics"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerSale"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sales"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerAppointments"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Appointments"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerServices"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Services"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<!-- STORE SECTION -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="STORE"
android:textColor="@color/text_light" android:textColor="@color/text_light"
android:textSize="11sp" android:textSize="11sp"
android:letterSpacing="0.15" android:letterSpacing="0.15"
@@ -111,57 +192,6 @@
android:textSize="15sp"/> android:textSize="15sp"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/drawerServices"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Services"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerSuppliers"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Suppliers"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerAppointments"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Appointments"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawerAdoptions" android:id="@+id/drawerAdoptions"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -179,23 +209,6 @@
android:textSize="15sp"/> android:textSize="15sp"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/drawerInventory"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Inventory"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawerProducts" android:id="@+id/drawerProducts"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -213,107 +226,125 @@
android:textSize="15sp"/> android:textSize="15sp"/>
</LinearLayout> </LinearLayout>
<!-- ADMIN SECTION -->
<LinearLayout <LinearLayout
android:id="@+id/drawerSale" android:id="@+id/sectionAdmin"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="vertical">
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sale"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerAnalytics"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Analytics" android:text="ADMIN"
android:textColor="@color/white" android:textColor="@color/text_light"
android:textSize="15sp"/> android:textSize="11sp"
</LinearLayout> android:letterSpacing="0.15"
android:paddingStart="16dp"
android:paddingTop="24dp"
android:paddingBottom="8dp"/>
<LinearLayout <LinearLayout
android:id="@+id/drawerStaff" android:id="@+id/drawerInventory"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground"
android:visibility="gone">
<TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
android:text="Staff Accounts" android:orientation="horizontal"
android:textColor="@color/white" android:gravity="center_vertical"
android:textSize="15sp"/> android:paddingStart="16dp"
</LinearLayout> android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Inventory"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawerPurchaseOrderView" android:id="@+id/drawerSuppliers"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
android:text="PurchaseOrder" android:orientation="horizontal"
android:textColor="@color/white" android:gravity="center_vertical"
android:textSize="15sp"/> android:paddingStart="16dp"
</LinearLayout> android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Suppliers"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawerProductSupplier" android:id="@+id/drawerCoupons"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
android:text="ProductSupplier" android:orientation="horizontal"
android:textColor="@color/white" android:gravity="center_vertical"
android:textSize="15sp"/> android:paddingStart="16dp"
</LinearLayout> android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Coupons"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/drawerCoupons" android:id="@+id/drawerPurchaseOrderView"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="48dp"
android:text="Coupons" android:orientation="horizontal"
android:textColor="@color/white" android:gravity="center_vertical"
android:textSize="15sp"/> android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Purchase Orders"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerProductSupplier"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Product Suppliers"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/drawerStaff"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?attr/selectableItemBackground">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Staff Accounts"
android:textColor="@color/white"
android:textSize="15sp"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>