diff --git a/public/locale/en.json b/public/locale/en.json index ab0afc7ca3c..4781623dcb1 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -484,6 +484,9 @@ "cancel": "Cancel", "cancel_appointment": "Cancel Appointment", "cancelled": "Cancelled", + "cannot_select_date_out_of_range": "Cannot select date out of range", + "cannot_select_month_out_of_range": "Cannot select month out of range", + "cannot_select_year_out_of_range": "Cannot select year out of range", "capture": "Capture", "capture_cover_photo": "Capture Cover Photo", "card": "Card", @@ -631,9 +634,12 @@ "copied_to_clipboard": "Copied to clipboard", "copilot_thinking": "Copilot is thinking...", "copy_phone_number": "Copy Phone Number", + "copying_is_not_allowed": "Copying is not allowed", "could_not_autofill": "We could not autofill any fields from what you said", "could_not_load_page": "We are facing some difficulties showing the Page you were looking for. Our Engineers have been notified and we'll make sure that this is resolved on the fly!", "countries_travelled": "Countries travelled", + "cover_image_deleted.": "Cover image deleted.", + "cover_image_updated.": "Cover image updated.", "covid_19_cat_gov": "Covid_19 Clinical Category as per Govt. of Kerala guideline (A/B/C)", "covid_19_death_reporting_form_1": "Covid-19 Death Reporting : Form 1", "covid_details": "Covid Details", @@ -728,6 +734,7 @@ "discontinued": "Discontinued", "disease_status": "Disease status", "district": "District", + "district_is_required_when_state_is_selected": "District is required when state is selected", "district_program_management_supporting_unit": "District Program Management Supporting Unit", "dob": "DOB", "dob_format": "Please enter date in DD/MM/YYYY format", @@ -907,7 +914,10 @@ "entered_in_error": "Entered in Error", "error_404": "Error 404", "error_deleting_shifting": "Error while deleting Shifting record", + "error_fetching_facility_data": "Error while fetching facility data", "error_fetching_slots_data": "Error while fetching slots data", + "error_fetching_user_data": "Error while fetching user data", + "error_fetching_user_details": "Error while fetching user details: ", "error_sending_otp": "Error while sending OTP, Please try again later", "error_updating_encounter": "Error to Updating Encounter", "error_verifying_otp": "Error while verifying OTP, Please request a new OTP", @@ -942,6 +952,7 @@ "facility_search_placeholder": "Search by Facility / District Name", "facility_search_placeholder_text": "Search by Facility name", "facility_type": "Facility Type", + "facility_updated_success": "Facility updated successfully", "failed_to_create_appointment": "Failed to create an appointment", "failed_to_link_abha_number": "Failed to link ABHA Number. Please try again later.", "fast_track_testing_reason": "Fast track testing reason", @@ -953,6 +964,10 @@ "fetched_attachments_successfully": "Fetched attachments successfully", "fetching": "Fetching", "field_required": "This field is required", + "file_archived_successfully": "File archived successfully", + "file_download_completed": "File download completed", + "file_download_failed": "Failed to download file", + "file_download_started": "Downloading file...", "file_error__choose_file": "Please choose a file to upload", "file_error__dynamic": "Error Uploading File: {{statusText}}", "file_error__file_name": "Please give a name for all files!", @@ -965,6 +980,7 @@ "file_list_headings__sample_report": "Sample Report", "file_list_headings__supporting_info": "Supporting Info", "file_name": "File Name", + "file_name_changed_successfully": "File name changed successfully", "file_preview": "File Preview", "file_preview_not_supported": "Can't preview this file. Try downloading it.", "file_type": "File Type", @@ -991,6 +1007,7 @@ "generated_summary_caution": "This is a computer generated summary using the information captured in the CARE system.", "generating": "Generating", "generating_discharge_summary": "Generating discharge summary", + "geolocation_is_not_supported_by_this_browser": "Geolocation is not supported by this browser", "get_auth_methods": "Get Available Authentication Methods", "get_auth_mode_error": "Could not find any supported authentication methods, Please try again with a different authentication method", "get_tests": "Get Tests", @@ -1157,6 +1174,7 @@ "location": "Location", "location_beds_empty": "No beds available in this location", "location_management": "Location Management", + "location_updated_successfully": "Location updated successfully", "log_lab_results": "Log Lab Results", "log_report": "Log Report", "log_update": "Log Update", @@ -1232,6 +1250,7 @@ "name_of_shifting_approving_facility": "Name of shifting approving facility", "nationality": "Nationality", "nearby_facilities": "Nearby Facilities", + "network_failure": "Network Failure. Please check your internet connectivity.", "never": "never", "never_logged_in": "Never Logged In", "new_password": "New Password", @@ -1295,6 +1314,7 @@ "no_staff": "No staff found", "no_tests_taken": "No tests taken", "no_treating_physicians_available": "This facility does not have any home facility doctors. Please contact your admin.", + "no_update_available": "No update available", "no_user_assigned": "No User Assigned to this patient", "no_users_found": "No Users Found", "no_vitals_present": "No Vitals Monitor present in this location or facility", @@ -1385,6 +1405,7 @@ "patient_consultation__treatment__summary__spo2": "SpO2", "patient_consultation__treatment__summary__temperature": "Temperature", "patient_created": "Patient Created", + "patient_created_successfully": "Patient created successfully", "patient_dashboard": "Patient Dashboard", "patient_details": "Patient Details", "patient_details_incomplete": "Patient Details Incomplete", @@ -1429,6 +1450,7 @@ "phone_number": "Phone Number", "phone_number_at_current_facility": "Phone Number of Contact person at current Facility", "phone_number_min_error": "Phone number must be at least 10 characters long", + "phone_number_not_found": "Phone number not found", "phone_number_verified": "Phone Number Verified", "pincode": "Pincode", "pincode_autofill": "State and District auto-filled from Pincode", @@ -1454,6 +1476,7 @@ "please_select_status": "Please select Status", "please_select_user_type": "Please select the User Type", "please_upload_a_csv_file": "Please Upload A CSV file", + "please_upload_an_image_file": "Please upload an image file!", "policy": "Policy", "policy__insurer": "Insurer", "policy__insurer__example": "GICOFINDIA", @@ -1505,6 +1528,7 @@ "professional_info_note_self": "View or update your professional information", "professional_info_note_view": "View user's professional information", "profile": "Profile", + "profile_picture_deleted": "Profile picture deleted", "proposed": "Proposed", "provisional": "Provisional", "qualification": "Qualification", @@ -1573,6 +1597,7 @@ "request_the_following_resource": "This is to request the following resource", "request_title": "Request Title", "request_title_placeholder": "Type your title here", + "request_updated_successfully": "Request updated successfully", "requested_by": "Requested By", "required": "Required", "required_quantity": "Required Quantity", @@ -1582,6 +1607,7 @@ "reset_password_note_self": "Enter your current password, then create and confirm your new password", "resource": "Resource", "resource_approving_facility": "Resource approving facility", + "resource_created_successfully": "Request created successfully", "resource_details": "Resource details", "resource_origin_facility": "Origin Facility", "resource_request": "Request", @@ -1671,6 +1697,7 @@ "select_time": "Select time", "select_time_slot": "Select time slot", "select_wards": "Select wards", + "selected_slot_not_found": "Selected Slot Not Found", "self_booked": "Self-booked", "send": "Send", "send_email": "Send Email", @@ -1693,7 +1720,6 @@ "sex": "Sex", "shared_by": "Shared By", "shift": "Shift Patient", - "shift_request_updated_successfully": "Shift request updated successfully", "shifting": "Shifting", "shifting_approval_facility": "Shifting approval facility", "shifting_approving_facility": "Shifting approving facility", @@ -1727,6 +1753,8 @@ "srf_id": "SRF ID", "staff": "Staff", "staff_list": "Staff List", + "staff_not_found": "Staff Not Found", + "staff_username_not_found": "Staff username not found", "start_consultation": "Start Consultation", "start_datetime": "Start Date/Time", "start_dosage": "Start Dosage", @@ -1806,6 +1834,7 @@ "type_your_comment": "Type your comment", "type_your_reason_here": "Type your reason here", "unable_to_get_current_position": "Unable to get current position.", + "unable_to_get_location: ": "Unable to get location: ", "unassign": "Unassign", "unconfirmed": "Unconfirmed", "unique_id": "Unique Id", diff --git a/src/Utils/Notifications.ts b/src/Utils/Notifications.ts index d4b38845ff1..68a7ed3f81c 100644 --- a/src/Utils/Notifications.ts +++ b/src/Utils/Notifications.ts @@ -43,30 +43,6 @@ const notifyError = (error: any) => { toast.error(errorMsg); }; -/** - * Success message handler - * @deprecated Use `toast.success` instead - */ -export const Success = ({ msg }: { msg: string }) => { - toast.success(msg); -}; - -/** - * Error message handler - * @deprecated Use `toast.error` instead - */ -export const Error = ({ msg }: { msg: any }) => { - notifyError(msg); -}; - -/** - * Warning message handler - * @deprecated Use `toast.warning` instead - */ -export const Warn = ({ msg }: { msg: string }) => { - toast.warning(msg); -}; - /** * 400 Bad Request handler * @deprecated TODO: add a better error handler diff --git a/src/Utils/request/errorHandler.ts b/src/Utils/request/errorHandler.ts index ef2eba8bfe8..ec3643ce9f7 100644 --- a/src/Utils/request/errorHandler.ts +++ b/src/Utils/request/errorHandler.ts @@ -1,3 +1,4 @@ +import { t } from "i18next"; import { navigate } from "raviger"; import { toast } from "sonner"; @@ -10,7 +11,7 @@ export function handleHttpError(error: Error) { } if (!(error instanceof HTTPError)) { - Notifications.Error({ msg: error.message || "Something went wrong!" }); + toast.error(error.message || t("something_went_wrong")); return; } @@ -21,7 +22,7 @@ export function handleHttpError(error: Error) { const cause = error.cause; if (isNotFound(error)) { - toast.error((cause?.detail as string) || "Not found"); + toast.error((cause?.detail as string) || t("not_found")); return; } @@ -40,9 +41,7 @@ export function handleHttpError(error: Error) { return; } - Notifications.Error({ - msg: cause?.detail || "Something went wrong...!", - }); + toast.error((cause?.detail as string) || t("something_went_wrong")); } function isSessionExpired(error: HTTPError["cause"]) { diff --git a/src/Utils/request/handleResponse.ts b/src/Utils/request/handleResponse.ts index c6f256185dc..df3a3a11ad7 100644 --- a/src/Utils/request/handleResponse.ts +++ b/src/Utils/request/handleResponse.ts @@ -1,4 +1,6 @@ +import { t } from "i18next"; import { navigate } from "raviger"; +import { toast } from "sonner"; import * as Notifications from "@/Utils/Notifications"; import { RequestResult } from "@/Utils/request/types"; @@ -15,7 +17,7 @@ export default function handleResponse( // 404 Not Found if (res.status === 404) { - notify?.Error({ msg: "Not Found" }); + toast.error(t("not_found")); return; } @@ -39,7 +41,7 @@ export default function handleResponse( return; } - notify?.Error({ msg: error?.detail || "Something went wrong...!" }); + toast.error((error?.detail as string) || t("something_went_wrong")); return; } } diff --git a/src/Utils/request/uploadFile.ts b/src/Utils/request/uploadFile.ts index 741325f41cf..9e62eefb799 100644 --- a/src/Utils/request/uploadFile.ts +++ b/src/Utils/request/uploadFile.ts @@ -1,4 +1,6 @@ +import { t } from "i18next"; import { Dispatch, SetStateAction } from "react"; +import { toast } from "sonner"; import * as Notification from "@/Utils/Notifications"; import { handleUploadPercentage } from "@/Utils/request/utils"; @@ -44,9 +46,7 @@ const uploadFile = async ( } xhr.onerror = () => { - Notification.Error({ - msg: "Network Failure. Please check your internet connectivity.", - }); + toast.error(t("network_failure")); onError(); reject(new Error("Network error")); }; diff --git a/src/Utils/request/utils.ts b/src/Utils/request/utils.ts index 86d9a51eebc..c821bbbaa08 100644 --- a/src/Utils/request/utils.ts +++ b/src/Utils/request/utils.ts @@ -1,8 +1,8 @@ import { Dispatch, SetStateAction } from "react"; +import { toast } from "sonner"; import { LocalStorageKeys } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import { QueryParams, RequestOptions } from "@/Utils/request/types"; export function makeUrl( @@ -50,7 +50,7 @@ const ensurePathNotMissingReplacements = (path: string) => { const msg = `Missing path params: ${missingParams.join( ", ", )}. Path: ${path}`; - Notification.Error({ msg }); + toast.error(msg); throw new Error(msg); } }; diff --git a/src/Utils/useSegmentedRecorder.ts b/src/Utils/useSegmentedRecorder.ts index 806e80064a2..b26215a6d26 100644 --- a/src/Utils/useSegmentedRecorder.ts +++ b/src/Utils/useSegmentedRecorder.ts @@ -1,7 +1,6 @@ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; - -import * as Notify from "@/Utils/Notifications"; +import { toast } from "sonner"; const useSegmentedRecording = () => { const [isRecording, setIsRecording] = useState(false); @@ -32,9 +31,7 @@ const useSegmentedRecording = () => { } }, () => { - Notify.Error({ - msg: t("audio__permission_message"), - }); + toast.error(t("audio__permission_message")); setIsRecording(false); setMicrophoneAccess(false); // Set access to false on failure }, diff --git a/src/Utils/useVoiceRecorder.ts b/src/Utils/useVoiceRecorder.ts index 119a5b24bf5..9f1163cd7d9 100644 --- a/src/Utils/useVoiceRecorder.ts +++ b/src/Utils/useVoiceRecorder.ts @@ -1,6 +1,5 @@ import { useEffect, useState } from "react"; - -import * as Notify from "./Notifications"; +import { toast } from "sonner"; const useVoiceRecorder = (handleMicPermission: (allowed: boolean) => void) => { const [audioURL, setAudioURL] = useState(""); @@ -30,9 +29,7 @@ const useVoiceRecorder = (handleMicPermission: (allowed: boolean) => void) => { error instanceof Error ? error.message : "Please grant microphone permission to record audio."; - Notify.Error({ - msg: errorMessage, - }); + toast.error(errorMessage); setIsRecording(false); handleMicPermission(false); } diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 65556f02bc8..0d918a4398e 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -1,10 +1,11 @@ import { differenceInMinutes, format } from "date-fns"; import html2canvas from "html2canvas"; +import { t } from "i18next"; +import { toast } from "sonner"; import { AREACODES, IN_LANDLINE_AREA_CODES } from "@/common/constants"; import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; -import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; import { Time } from "@/Utils/types"; import { DoseRange, Timing } from "@/types/emr/medicationRequest"; @@ -644,9 +645,9 @@ export const saveElementAsImage = async (id: string, filename: string) => { export const copyToClipboard = async (content: string) => { try { await navigator.clipboard.writeText(content); - Notification.Success({ msg: "Copied to clipboard" }); + toast.success(t("copied_to_clipboard")); } catch (err) { - Notification.Error({ msg: "Copying is not allowed" }); + toast.error(t("copying_is_not_allowed")); } }; diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index 8858d33be0e..1bd8747e66d 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -29,7 +29,6 @@ import BrowserWarning from "@/components/ErrorPages/BrowserWarning"; import { useAuthContext } from "@/hooks/useAuthUser"; import FiltersCache from "@/Utils/FiltersCache"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import request from "@/Utils/request/request"; @@ -170,7 +169,7 @@ const Login = (props: LoginProps) => { errorMessage = error.message; } setOtpValidationError(errorMessage); - Notification.Error({ msg: errorMessage }); + toast.error(errorMessage); }, }); diff --git a/src/components/Auth/ResetPassword.tsx b/src/components/Auth/ResetPassword.tsx index 6986331e6f8..9f14576aadc 100644 --- a/src/components/Auth/ResetPassword.tsx +++ b/src/components/Auth/ResetPassword.tsx @@ -1,6 +1,7 @@ import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -10,7 +11,6 @@ import { validateRule } from "@/components/Users/UserFormValidations"; import { LocalStorageKeys } from "@/common/constants"; import { validatePassword } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; @@ -82,9 +82,7 @@ const ResetPassword = (props: ResetPasswordProps) => { }); if (res?.ok) { localStorage.removeItem(LocalStorageKeys.accessToken); - Notification.Success({ - msg: t("password_reset_success"), - }); + toast.success(t("password_reset_success")); navigate("/login"); } else if (res && error) { setErrors(error); diff --git a/src/components/Common/AvatarEditModal.tsx b/src/components/Common/AvatarEditModal.tsx index 47163532b84..d5044c66533 100644 --- a/src/components/Common/AvatarEditModal.tsx +++ b/src/components/Common/AvatarEditModal.tsx @@ -7,6 +7,7 @@ import React, { } from "react"; import { useTranslation } from "react-i18next"; import Webcam from "react-webcam"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -16,8 +17,6 @@ import DialogModal from "@/components/Common/Dialog"; import useDragAndDrop from "@/hooks/useDragAndDrop"; -import { Warn } from "@/Utils/Notifications"; - interface Props { title: string; open: boolean; @@ -108,7 +107,7 @@ const AvatarEditModal = ({ return; } if (!isImageFile(e.target.files[0])) { - Warn({ msg: "Please upload an image file!" }); + toast.warning(t("please_upload_an_image_file")); return; } setSelectedFile(e.target.files[0]); @@ -340,7 +339,7 @@ const AvatarEditModal = ({ videoConstraints={constraint} onUserMediaError={(_e) => { setIsCameraOpen(false); - Warn({ msg: t("camera_permission_denied") }); + toast.warning(t("camera_permission_denied")); }} /> diff --git a/src/components/Common/DateInputV2.tsx b/src/components/Common/DateInputV2.tsx index 26c6a702c50..88accefa070 100644 --- a/src/components/Common/DateInputV2.tsx +++ b/src/components/Common/DateInputV2.tsx @@ -1,12 +1,12 @@ import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; import { t } from "i18next"; import { MutableRefObject, useEffect, useRef, useState } from "react"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; import DateTextInput from "@/components/Common/DateTextInput"; -import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; import { useValueInjectionObserver } from "@/Utils/useValueInjectionObserver"; import { classNames } from "@/Utils/utils"; @@ -149,9 +149,9 @@ const DateInputV2: React.FC = ({ setIsOpen?.(false); } })() - : Notification.Error({ - msg: outOfLimitsErrorMessage ?? "Cannot select date out of range", - }); + : toast.error( + outOfLimitsErrorMessage ?? t("cannot_select_date_out_of_range"), + ); }; const handleTimeChange = (options: { @@ -265,9 +265,9 @@ const DateInputV2: React.FC = ({ ); setType("date"); } else { - Notification.Error({ - msg: outOfLimitsErrorMessage ?? "Cannot select month out of range", - }); + toast.error( + outOfLimitsErrorMessage ?? t("cannot_select_month_out_of_range"), + ); } }; //min and max setting for year @@ -291,9 +291,9 @@ const DateInputV2: React.FC = ({ } setType("date"); } else { - Notification.Error({ - msg: outOfLimitsErrorMessage ?? "Cannot select year out of range", - }); + toast.error( + outOfLimitsErrorMessage ?? t("cannot_select_year_out_of_range"), + ); } }; diff --git a/src/components/Common/ExcelFIleDragAndDrop.tsx b/src/components/Common/ExcelFIleDragAndDrop.tsx index 86902a9b189..06e99e9df5f 100644 --- a/src/components/Common/ExcelFIleDragAndDrop.tsx +++ b/src/components/Common/ExcelFIleDragAndDrop.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as XLSX from "xlsx"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -16,8 +17,6 @@ import schemaParser, { SchemaType, } from "@/common/schemaParser"; -import * as Notification from "@/Utils/Notifications"; - interface Props { handleSubmit: (data: any) => void; loading: boolean; @@ -83,9 +82,7 @@ export default function ExcelFileDragAndDrop({ reader.readAsBinaryString(file); } catch (e: any) { - Notification.Error({ - msg: e.message, - }); + toast.error(e.message); } }; diff --git a/src/components/Facility/CreateFacilityForm.tsx b/src/components/Facility/CreateFacilityForm.tsx index ed5c87caabc..d3c73213422 100644 --- a/src/components/Facility/CreateFacilityForm.tsx +++ b/src/components/Facility/CreateFacilityForm.tsx @@ -3,6 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -36,7 +37,6 @@ import { validatePincode, } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import { parsePhoneNumber } from "@/Utils/utils"; @@ -101,9 +101,7 @@ export default function CreateFacilityForm({ const { mutate: createFacility, isPending } = useMutation({ mutationFn: mutate(routes.facility.create), onSuccess: (_data: BaseFacility) => { - Notification.Success({ - msg: t("facility_added_successfully"), - }); + toast.success(t("facility_added_successfully")); queryClient.invalidateQueries({ queryKey: ["organizationFacilities"] }); form.reset(); onSubmitSuccess?.(); @@ -112,12 +110,10 @@ export default function CreateFacilityForm({ const errorData = error.cause as { errors: { msg: string[] } }; if (errorData?.errors?.msg) { errorData.errors.msg.forEach((msg) => { - Notification.Error({ msg }); + toast.error(msg); }); } else { - Notification.Error({ - msg: t("facility_add_error"), - }); + toast.error(t("facility_add_error")); } }, }); @@ -143,22 +139,16 @@ export default function CreateFacilityForm({ form.setValue("latitude", position.coords.latitude.toString()); form.setValue("longitude", position.coords.longitude.toString()); setIsGettingLocation(false); - Notification.Success({ - msg: "Location updated successfully", - }); + toast.success(t("location_updated_successfully")); }, (error) => { setIsGettingLocation(false); - Notification.Error({ - msg: "Unable to get location: " + error.message, - }); + toast.error(t("unable_to_get_location") + error.message); }, { timeout: 10000 }, // 10 second timeout ); } else { - Notification.Error({ - msg: "Geolocation is not supported by this browser", - }); + toast.error(t("geolocation_is_not_supported_by_this_browser")); } }; diff --git a/src/components/Facility/FacilityCreate.tsx b/src/components/Facility/FacilityCreate.tsx index f5c3fecd40b..59b87633a8f 100644 --- a/src/components/Facility/FacilityCreate.tsx +++ b/src/components/Facility/FacilityCreate.tsx @@ -10,6 +10,7 @@ import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import Card from "@/CAREUI/display/Card"; @@ -55,7 +56,6 @@ import { validatePincode, } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; @@ -143,7 +143,6 @@ export const FacilityCreate = (props: FacilityProps) => { // Update form when facility data is loaded useEffect(() => { if (facilityData) { - console.log(facilityData); form.reset({ facility_type: facilityData.facility_type, name: facilityData.name, @@ -202,11 +201,11 @@ export const FacilityCreate = (props: FacilityProps) => { }); if (res?.ok && responseData) { - Notification.Success({ - msg: facilityId - ? "Facility updated successfully" - : "Facility added successfully", - }); + toast.success( + facilityId + ? t("facility_updated_success") + : t("facility_added_successfully"), + ); navigate(`/facility/${responseData.id}`); } } catch (error) { diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index 3eba20f4765..4ec23fe5a65 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -4,6 +4,7 @@ import { Hospital, MapPin, MoreVertical, Settings, Trash2 } from "lucide-react"; import { navigate } from "raviger"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -26,7 +27,6 @@ import useAuthUser from "@/hooks/useAuthUser"; import { FACILITY_FEATURE_TYPES } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; @@ -122,9 +122,9 @@ export const FacilityHome = ({ facilityId }: Props) => { pathParams: { id: facilityId }, onResponse: ({ res }) => { if (res?.ok) { - Notification.Success({ - msg: t("deleted_successfully", { name: facilityData?.name }), - }); + toast.success( + t("deleted_successfully", { name: facilityData?.name }), + ); } navigate("/facility"); }, @@ -145,7 +145,7 @@ export const FacilityHome = ({ facilityId }: Props) => { if (xhr.status === 200) { await sleep(1000); facilityFetch(); - Notification.Success({ msg: "Cover image updated." }); + toast.success(t("cover_image_updated")); setEditCoverImage(false); } else { onError(); @@ -163,7 +163,7 @@ export const FacilityHome = ({ facilityId }: Props) => { pathParams: { id: facilityId }, }); if (res?.ok) { - Notification.Success({ msg: "Cover image deleted" }); + toast.success(t("cover_image_deleted")); facilityFetch(); setEditCoverImage(false); } else { diff --git a/src/components/Files/AudioCaptureDialog.tsx b/src/components/Files/AudioCaptureDialog.tsx index d198ac7db16..05488d305e0 100644 --- a/src/components/Files/AudioCaptureDialog.tsx +++ b/src/components/Files/AudioCaptureDialog.tsx @@ -1,13 +1,12 @@ import { Link } from "raviger"; import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; import { useTimer } from "@/hooks/useTimer"; -import * as Notify from "@/Utils/Notifications"; - import useVoiceRecorder from "../../Utils/useVoiceRecorder"; export interface AudioCaptureDialogProps { @@ -50,9 +49,7 @@ export default function AudioCaptureDialog(props: AudioCaptureDialogProps) { timer.start(); }) .catch(() => { - Notify.Error({ - msg: t("audio__permission_message"), - }); + toast.error(t("audio__permission_message")); setStatus("PERMISSION_DENIED"); }); }; diff --git a/src/components/Files/CameraCaptureDialog.tsx b/src/components/Files/CameraCaptureDialog.tsx index 0a9e3fc39ad..cfbaff19dab 100644 --- a/src/components/Files/CameraCaptureDialog.tsx +++ b/src/components/Files/CameraCaptureDialog.tsx @@ -1,6 +1,7 @@ import { t } from "i18next"; import { useCallback, useEffect, useRef, useState } from "react"; import Webcam from "react-webcam"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -10,8 +11,6 @@ import DialogModal from "@/components/Common/Dialog"; import useBreakpoints from "@/hooks/useBreakpoints"; -import * as Notify from "@/Utils/Notifications"; - export interface CameraCaptureDialogProps { show: boolean; onHide: () => void; @@ -44,9 +43,7 @@ export default function CameraCaptureDialog(props: CameraCaptureDialogProps) { stream = mediaStream; }) .catch(() => { - Notify.Warn({ - msg: t("camera_permission_denied"), - }); + toast.warning(t("camera_permission_denied")); onHide(); }); @@ -72,9 +69,7 @@ export default function CameraCaptureDialog(props: CameraCaptureDialogProps) { prevMode === "environment" ? "user" : "environment", ); } else { - Notify.Warn({ - msg: t("switch_camera_is_not_available"), - }); + toast.warning(t("switch_camera_is_not_available")); } }, []); diff --git a/src/components/Form/Form.tsx b/src/components/Form/Form.tsx index 38a4cb0818b..374bec7cf3a 100644 --- a/src/components/Form/Form.tsx +++ b/src/components/Form/Form.tsx @@ -1,4 +1,5 @@ import { useEffect, useMemo, useRef, useState } from "react"; +import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -16,7 +17,6 @@ import { } from "@/components/Form/Utils"; import { DraftSection, useAutoSaveReducer } from "@/Utils/AutoSave"; -import * as Notification from "@/Utils/Notifications"; import { classNames, isEmpty, omitBy } from "@/Utils/utils"; type Props = { @@ -74,7 +74,7 @@ const Form = ({ dispatch({ type: "set_errors", errors }); if (errors.$all) { - Notification.Error({ msg: errors.$all }); + toast.error(errors.$all); } return; } diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index f970011e221..aa00d2e1c27 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -2,6 +2,7 @@ import dayjs from "dayjs"; import { navigate } from "raviger"; import { Fragment, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -11,7 +12,6 @@ import { PatientProps } from "@/components/Patient/PatientDetailsTab"; import { GENDER_TYPES } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import { formatPatientAge } from "@/Utils/utils"; import { Organization, @@ -94,9 +94,7 @@ export const Demography = (props: PatientProps) => { const withPermissionCheck = (action: () => void) => () => { if (!hasEditPermission()) { - Notification.Error({ - msg: t("permission_denied"), - }); + toast.error(t("permission_denied")); return; } action(); diff --git a/src/components/Patient/PatientRegistration.tsx b/src/components/Patient/PatientRegistration.tsx index 94289124403..36ac706c23b 100644 --- a/src/components/Patient/PatientRegistration.tsx +++ b/src/components/Patient/PatientRegistration.tsx @@ -3,6 +3,7 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { navigate, useQueryParams } from "raviger"; import { Fragment, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import SectionNavigator from "@/CAREUI/misc/SectionNavigator"; @@ -35,7 +36,6 @@ import { import countryList from "@/common/static/countries.json"; import { validatePincode } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; @@ -123,9 +123,7 @@ export default function PatientRegistration( const createPatientMutation = useMutation({ mutationFn: mutate(routes.addPatient), onSuccess: (resp: PatientModel) => { - Notification.Success({ - msg: t("patient_registration_success"), - }); + toast.success(t("patient_registration_success")); // Lets navigate the user to the verify page as the patient is not accessible to the user yet navigate(`/facility/${facilityId}/patients/verify`, { query: { @@ -139,9 +137,7 @@ export default function PatientRegistration( }); }, onError: () => { - Notification.Error({ - msg: t("patient_registration_error"), - }); + toast.error(t("patient_registration_error")); }, }); @@ -150,15 +146,11 @@ export default function PatientRegistration( pathParams: { id: patientId || "" }, }), onSuccess: () => { - Notification.Success({ - msg: t("patient_update_success"), - }); + toast.success(t("patient_update_success")); goBack(); }, onError: () => { - Notification.Error({ - msg: t("patient_update_error"), - }); + toast.error(t("patient_update_error")); }, }); @@ -265,9 +257,7 @@ export default function PatientRegistration( if (firstErrorField) { firstErrorField.scrollIntoView({ behavior: "smooth", block: "center" }); } - Notification.Error({ - msg: t("please_fix_errors"), - }); + toast.error(t("please_fix_errors")); setFeErrors(validate); } }; diff --git a/src/components/Resource/ResourceCommentSection.tsx b/src/components/Resource/ResourceCommentSection.tsx index 777284b7c7f..a556f33a186 100644 --- a/src/components/Resource/ResourceCommentSection.tsx +++ b/src/components/Resource/ResourceCommentSection.tsx @@ -1,4 +1,6 @@ +import { t } from "i18next"; import { useState } from "react"; +import { toast } from "sonner"; import PaginatedList from "@/CAREUI/misc/PaginatedList"; @@ -7,7 +9,6 @@ import { Button } from "@/components/ui/button"; import CircularProgress from "@/components/Common/CircularProgress"; import TextAreaFormField from "@/components/Form/FormFields/TextAreaFormField"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import { formatName } from "@/Utils/utils"; @@ -23,9 +24,7 @@ const CommentSection = (props: { id: string }) => { comment: commentBox, }; if (!/\S+/.test(commentBox)) { - Notification.Error({ - msg: "Comment Should Contain At Least 1 Character", - }); + toast.error(t("comment_min_length")); return; } const { res } = await request(routes.addResourceComments, { @@ -33,7 +32,7 @@ const CommentSection = (props: { id: string }) => { body: payload, }); if (res?.ok) { - Notification.Success({ msg: "Comment added successfully" }); + toast.success(t("comment_added_successfully")); } setCommentBox(""); }; diff --git a/src/components/Resource/ResourceCreate.tsx b/src/components/Resource/ResourceCreate.tsx index e0f199af7ad..9838b78c8ef 100644 --- a/src/components/Resource/ResourceCreate.tsx +++ b/src/components/Resource/ResourceCreate.tsx @@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { navigate, useQueryParams } from "raviger"; import { useReducer, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import Card from "@/CAREUI/display/Card"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -25,7 +26,6 @@ import useAppHistory from "@/hooks/useAppHistory"; import { RESOURCE_CATEGORY_CHOICES } from "@/common/constants"; import { phonePreg } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; @@ -204,10 +204,7 @@ export default function ResourceCreate(props: resourceProps) { if (res?.ok && data) { await dispatch({ type: "set_form", form: initForm }); - Notification.Success({ - msg: "Request created successfully", - }); - + toast.success(t("resource_created_successfully")); navigate(`/resource/${data.id}`); } } diff --git a/src/components/Resource/ResourceDetailsUpdate.tsx b/src/components/Resource/ResourceDetailsUpdate.tsx index edeb252d7e0..f8197b481a0 100644 --- a/src/components/Resource/ResourceDetailsUpdate.tsx +++ b/src/components/Resource/ResourceDetailsUpdate.tsx @@ -1,6 +1,7 @@ import { t } from "i18next"; import { navigate, useQueryParams } from "raviger"; import { useReducer, useState } from "react"; +import { toast } from "sonner"; import Card from "@/CAREUI/display/Card"; @@ -23,7 +24,6 @@ import useAppHistory from "@/hooks/useAppHistory"; import { RESOURCE_CHOICES } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; @@ -178,10 +178,7 @@ export const ResourceDetailsUpdate = (props: resourceProps) => { if (res && res.status == 200 && data) { dispatch({ type: "set_form", form: data }); - Notification.Success({ - msg: "Request updated successfully", - }); - + toast.success(t("request_updated_successfully")); navigate(`/resource/${props.id}`); } else { setIsLoading(false); diff --git a/src/components/Users/CreateUserForm.tsx b/src/components/Users/CreateUserForm.tsx index 6c1e9483b50..93d3eeb8d51 100644 --- a/src/components/Users/CreateUserForm.tsx +++ b/src/components/Users/CreateUserForm.tsx @@ -3,6 +3,7 @@ import { useQuery } from "@tanstack/react-query"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import * as z from "zod"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -30,7 +31,6 @@ import { validateRule } from "@/components/Users/UserFormValidations"; import { GENDER_TYPES } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; import OrganizationSelector from "@/pages/Organization/components/OrganizationSelector"; @@ -176,19 +176,13 @@ export default function CreateUserForm({ onSubmitSuccess }: Props) { }); if (res?.ok) { - Notification.Success({ - msg: t("user_added_successfully"), - }); + toast.success(t("user_added_successfully")); onSubmitSuccess?.(user!); } else { - Notification.Error({ - msg: error?.message ?? t("user_add_error"), - }); + toast.error((error?.message as string) ?? t("user_add_error")); } } catch (error) { - Notification.Error({ - msg: t("user_add_error"), - }); + toast.error(t("user_add_error")); } }; diff --git a/src/components/Users/UserAvatar.tsx b/src/components/Users/UserAvatar.tsx index e6493e526ca..e4c7f783f20 100644 --- a/src/components/Users/UserAvatar.tsx +++ b/src/components/Users/UserAvatar.tsx @@ -1,6 +1,7 @@ import careConfig from "@careConfig"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { TooltipComponent } from "@/components/ui/tooltip"; @@ -11,7 +12,6 @@ import Loading from "@/components/Common/Loading"; import useAuthUser from "@/hooks/useAuthUser"; -import * as Notification from "@/Utils/Notifications"; import { showAvatarEdit } from "@/Utils/permissions"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; @@ -58,7 +58,7 @@ export default function UserAvatar({ if (xhr.status === 200) { await sleep(1000); refetchUserData?.(); - Notification.Success({ msg: t("avatar_updated_success") }); + toast.success(t("avatar_updated_success")); setEditAvatar(false); } }, @@ -74,7 +74,7 @@ export default function UserAvatar({ pathParams: { username }, }); if (res?.ok) { - Notification.Success({ msg: "Profile picture deleted" }); + toast.success(t("profile_picture_deleted")); refetchUserData?.(); setEditAvatar(false); } else { diff --git a/src/components/Users/UserFilter.tsx b/src/components/Users/UserFilter.tsx index 66cac45b44a..95a365727ee 100644 --- a/src/components/Users/UserFilter.tsx +++ b/src/components/Users/UserFilter.tsx @@ -1,3 +1,6 @@ +import { t } from "i18next"; +import { toast } from "sonner"; + import FiltersSlideover from "@/CAREUI/interactive/FiltersSlideover"; import { FieldLabel } from "@/components/Form/FormFields/FormField"; @@ -12,7 +15,6 @@ import { USER_TYPE_OPTIONS, } from "@/common/constants"; -import * as Notify from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { parsePhoneNumber } from "@/Utils/utils"; @@ -69,9 +71,7 @@ export default function UserFilter(props: any) { last_active_days: last_active_days || "", }; if (state && !district) { - Notify.Warn({ - msg: "District is required when state is selected", - }); + toast.warning(t("district_is_required_when_state_is_selected")); return; } onChange(data); diff --git a/src/components/Users/UserHome.tsx b/src/components/Users/UserHome.tsx index b07f8f87461..1df7d11d95e 100644 --- a/src/components/Users/UserHome.tsx +++ b/src/components/Users/UserHome.tsx @@ -1,6 +1,7 @@ import { Link, navigate } from "raviger"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; @@ -12,7 +13,6 @@ import UserSummaryTab from "@/components/Users/UserSummary"; import useAuthUser from "@/hooks/useAuthUser"; -import * as Notification from "@/Utils/Notifications"; import { editUserPermissions } from "@/Utils/permissions"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; @@ -52,16 +52,14 @@ export default function UserHome(props: UserHomeProps) { } else if (res?.status === 400) { navigate("/users"); } else if (error) { - Notification.Error({ - msg: "Error while fetching user details: " + (error?.message || ""), - }); + toast.error( + t("error_fetching_user_details") + (error?.message || ""), + ); } }, }, ); - console.log(userData); - if (loading || !userData) { return ; } diff --git a/src/components/Users/UserResetPassword.tsx b/src/components/Users/UserResetPassword.tsx index 2ceae7314ae..e30155f5eba 100644 --- a/src/components/Users/UserResetPassword.tsx +++ b/src/components/Users/UserResetPassword.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -10,7 +11,6 @@ import TextFormField from "@/components/Form/FormFields/TextFormField"; import { validateRule } from "@/components/Users/UserFormValidations"; import { UpdatePasswordForm } from "@/components/Users/models"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import { UserBase } from "@/types/user/user"; @@ -89,11 +89,9 @@ export default function UserResetPassword({ }); if (res?.ok) { - Notification.Success({ msg: data?.message as string }); + toast.success(data?.message as string); } else { - Notification.Error({ - msg: error?.message ?? t("password_update_error"), - }); + toast.error((error?.message as string) ?? t("password_update_error")); } setisSubmitting(false); }; diff --git a/src/components/Users/UserSoftwareUpdate.tsx b/src/components/Users/UserSoftwareUpdate.tsx index 5cc685f575d..83b99987550 100644 --- a/src/components/Users/UserSoftwareUpdate.tsx +++ b/src/components/Users/UserSoftwareUpdate.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -7,8 +8,6 @@ import { Button } from "@/components/ui/button"; import UpdatableApp, { checkForUpdate } from "@/components/Common/UpdatableApp"; -import * as Notification from "@/Utils/Notifications"; - export default function UserSoftwareUpdate() { const [updateStatus, setUpdateStatus] = useState({ isChecking: false, @@ -29,9 +28,7 @@ export default function UserSoftwareUpdate() { isUpdateAvailable: false, isChecking: false, }); - Notification.Success({ - msg: "No update available", - }); + toast.success(t("no_update_available")); } }; diff --git a/src/components/Users/UserSummary.tsx b/src/components/Users/UserSummary.tsx index 397396abc8e..4cb198528df 100644 --- a/src/components/Users/UserSummary.tsx +++ b/src/components/Users/UserSummary.tsx @@ -1,6 +1,7 @@ import { navigate } from "raviger"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; @@ -18,7 +19,6 @@ import { import useAuthUser from "@/hooks/useAuthUser"; -import * as Notification from "@/Utils/Notifications"; import { editUserPermissions, showAvatarEdit, @@ -54,15 +54,11 @@ export default function UserSummaryTab({ }); setIsDeleting(false); if (res?.status === 204) { - Notification.Success({ - msg: t("user_deleted_successfully"), - }); + toast.success(t("user_deleted_successfully")); setshowDeleteDialog(!showDeleteDialog); navigate("/users"); } else { - Notification.Error({ - msg: t("user_delete_error") + ": " + (error || ""), - }); + toast.error(t("user_delete_error") + ": " + (error || "")); setshowDeleteDialog(!showDeleteDialog); } }; diff --git a/src/hooks/useFileManager.tsx b/src/hooks/useFileManager.tsx index 3c1660e3674..e6c92ff5166 100644 --- a/src/hooks/useFileManager.tsx +++ b/src/hooks/useFileManager.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { t } from "i18next"; import { useState } from "react"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -18,7 +19,6 @@ import { PREVIEWABLE_FILE_EXTENSIONS, } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; @@ -146,7 +146,7 @@ export default function useFileManager( pathParams: { id: body.id }, })({} as any), onSuccess: () => { - Notification.Success({ msg: "File archived successfully" }); + toast.success(t("file_archived_successfully")); queryClient.invalidateQueries({ queryKey: [`${fileType}-files`, archiveDialogueOpen?.associating_id], }); @@ -215,7 +215,7 @@ export default function useFileManager( pathParams: { id: body.id }, })(body), onSuccess: (_, { associating_id }) => { - Notification.Success({ msg: "File name changed successfully" }); + toast.success(t("file_name_changed_successfully")); setEditDialogueOpen(null); onEdit && onEdit(); queryClient.invalidateQueries({ @@ -489,7 +489,7 @@ export default function useFileManager( ) => { try { if (!file.id) return; - Notification.Success({ msg: "Downloading file..." }); + toast.success(t("file_download_started")); const fileData = await retrieveUpload(file, associating_id); const response = await fetch(fileData?.read_signed_url || ""); if (!response.ok) throw new Error("Network response was not ok."); @@ -506,8 +506,9 @@ export default function useFileManager( // Clean up window.URL.revokeObjectURL(blobUrl); document.body.removeChild(a); + toast.success(t("file_download_completed")); } catch (err) { - Notification.Error({ msg: "Failed to download file" }); + toast.error(t("file_download_failed")); } }; diff --git a/src/hooks/useFileUpload.tsx b/src/hooks/useFileUpload.tsx index d8aea1fa1b1..d5884dddd02 100644 --- a/src/hooks/useFileUpload.tsx +++ b/src/hooks/useFileUpload.tsx @@ -8,6 +8,7 @@ import { useEffect, useState, } from "react"; +import { toast } from "sonner"; import AudioCaptureDialog from "@/components/Files/AudioCaptureDialog"; import CameraCaptureDialog from "@/components/Files/CameraCaptureDialog"; @@ -19,7 +20,6 @@ import { import { DEFAULT_ALLOWED_EXTENSIONS } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import uploadFile from "@/Utils/request/uploadFile"; @@ -187,25 +187,21 @@ export default function useFileUpload( (xhr: XMLHttpRequest) => { if (xhr.status >= 200 && xhr.status < 300) { setProgress(null); - Notification.Success({ - msg: t("file_uploaded"), - }); + toast.success(t("file_uploaded")); setError(null); onUpload && onUpload(data); resolve(); } else { - Notification.Error({ - msg: t("file_error__dynamic", { statusText: xhr.statusText }), - }); + toast.error( + t("file_error__dynamic", { statusText: xhr.statusText }), + ); setProgress(null); reject(); } }, setProgress as any, () => { - Notification.Error({ - msg: t("file_error__network"), - }); + toast.error(t("file_error__network")); setProgress(null); reject(); }, diff --git a/src/pages/Appoinments/PatientRegistration.tsx b/src/pages/Appoinments/PatientRegistration.tsx index b48cb640b53..ad75bf92295 100644 --- a/src/pages/Appoinments/PatientRegistration.tsx +++ b/src/pages/Appoinments/PatientRegistration.tsx @@ -4,6 +4,7 @@ import { navigate } from "raviger"; import { Fragment } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { z } from "zod"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -34,7 +35,6 @@ import { usePatientContext } from "@/hooks/usePatientUser"; import { GENDER_TYPES } from "@/common/constants"; import { validateName, validatePincode } from "@/common/validation"; -import * as Notification from "@/Utils/Notifications"; import { usePubSub } from "@/Utils/pubsubContext"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; @@ -150,7 +150,7 @@ export function PatientRegistration(props: PatientRegistrationProps) { }, })(body), onSuccess: (data: Appointment) => { - Notification.Success({ msg: t("appointment_created_success") }); + toast.success(t("appointment_created_success")); queryClient.invalidateQueries({ queryKey: [ ["patients", tokenData.phoneNumber], @@ -165,9 +165,7 @@ export function PatientRegistration(props: PatientRegistrationProps) { ); }, onError: (error) => { - Notification.Error({ - msg: error?.message || t("failed_to_create_appointment"), - }); + toast.error(error?.message || t("failed_to_create_appointment")); }, }); @@ -180,7 +178,7 @@ export function PatientRegistration(props: PatientRegistrationProps) { }, })(body), onSuccess: (data: AppointmentPatient) => { - Notification.Success({ msg: "Patient created successfully" }); + toast.success(t("patient_created_successfully")); publish("patient:upsert", data); createAppointment({ patient: data.id, @@ -192,13 +190,9 @@ export function PatientRegistration(props: PatientRegistrationProps) { const errors = errorData?.errors; if (Array.isArray(errors) && errors.length > 0) { const firstError = errors[0]; - Notification.Error({ - msg: firstError.msg, - }); + toast.error(firstError.msg); } else { - Notification.Error({ - msg: error.message, - }); + toast.error(error.message); } }, }); diff --git a/src/pages/Appoinments/PatientSelect.tsx b/src/pages/Appoinments/PatientSelect.tsx index 2dffd1bcbfb..755f3936893 100644 --- a/src/pages/Appoinments/PatientSelect.tsx +++ b/src/pages/Appoinments/PatientSelect.tsx @@ -3,6 +3,7 @@ import dayjs from "dayjs"; import { navigate } from "raviger"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -17,7 +18,6 @@ import { import { usePatientContext } from "@/hooks/usePatientUser"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; @@ -45,13 +45,13 @@ export default function PatientSelect({ const queryClient = useQueryClient(); if (!staffId) { - Notification.Error({ msg: "Staff Not Found" }); + toast.error(t("staff_not_found")); navigate(`/facility/${facilityId}/`); } else if (!tokenData) { - Notification.Error({ msg: "Phone Number Not Found" }); + toast.error(t("phone_number_not_found")); navigate(`/facility/${facilityId}/appointments/${staffId}/otp/send`); } else if (!selectedSlot) { - Notification.Error({ msg: "Selected Slot Not Found" }); + toast.error(t("selected_slot_not_found")); navigate( `/facility/${facilityId}/appointments/${staffId}/book-appointment`, ); @@ -80,7 +80,7 @@ export default function PatientSelect({ }, })(body), onSuccess: (data: Appointment) => { - Notification.Success({ msg: t("appointment_created_success") }); + toast.success(t("appointment_created_success")); queryClient.invalidateQueries({ queryKey: [ ["patients", tokenData.phoneNumber], @@ -92,9 +92,7 @@ export default function PatientSelect({ }); }, onError: (error) => { - Notification.Error({ - msg: error?.message || t("failed_to_create_appointment"), - }); + toast.error(error?.message || t("failed_to_create_appointment")); }, }); diff --git a/src/pages/Appoinments/Schedule.tsx b/src/pages/Appoinments/Schedule.tsx index a26b8bf3ad7..4e43f00d75c 100644 --- a/src/pages/Appoinments/Schedule.tsx +++ b/src/pages/Appoinments/Schedule.tsx @@ -3,6 +3,7 @@ import dayjs from "dayjs"; import { Link, navigate } from "raviger"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { cn } from "@/lib/utils"; @@ -22,7 +23,6 @@ import { SlotAvailability } from "@/components/Schedule/types"; import { usePatientContext } from "@/hooks/usePatientUser"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; @@ -47,10 +47,10 @@ export function ScheduleAppointment(props: AppointmentsProps) { const tokenData = patientUserContext?.tokenData; if (!staffId) { - Notification.Error({ msg: "Staff username not found" }); + toast.error(t("staff_username_not_found")); navigate(`/facility/${facilityId}/`); } else if (!tokenData) { - Notification.Error({ msg: "Phone number not found" }); + toast.error(t("phone_number_not_found")); navigate(`/facility/${facilityId}/appointments/${staffId}/otp/send`); } @@ -66,7 +66,7 @@ export function ScheduleAppointment(props: AppointmentsProps) { }); if (facilityError) { - Notification.Error({ msg: "Error while fetching facility data" }); + toast.error(t("error_fetching_facility_data")); } const { data: userData, error: userError } = useQuery({ @@ -78,7 +78,7 @@ export function ScheduleAppointment(props: AppointmentsProps) { }); if (userError) { - Notification.Error({ msg: "Error while fetching user data" }); + toast.error(t("error_fetching_user_data")); } const slotsQuery = useQuery<{ results: SlotAvailability[] }>({ @@ -103,11 +103,9 @@ export function ScheduleAppointment(props: AppointmentsProps) { Array.isArray(slotsQuery.error.cause.errors) && slotsQuery.error.cause.errors[0][0] === "Resource is not schedulable" ) { - Notification.Error({ - msg: t("user_not_available_for_appointments"), - }); + toast.error(t("user_not_available_for_appointments")); } else { - Notification.Error({ msg: t("error_fetching_slots_data") }); + toast.error(t("error_fetching_slots_data")); } } diff --git a/src/pages/Appoinments/Success.tsx b/src/pages/Appoinments/Success.tsx index 7a7ae0399fc..3a4c40f6dac 100644 --- a/src/pages/Appoinments/Success.tsx +++ b/src/pages/Appoinments/Success.tsx @@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { format } from "date-fns"; import dayjs from "dayjs"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -10,7 +11,6 @@ import { UserModel } from "@/components/Users/models"; import { usePatientContext } from "@/hooks/usePatientUser"; -import * as Notification from "@/Utils/Notifications"; import query from "@/Utils/request/query"; import { formatName } from "@/Utils/utils"; import PublicAppointmentApi from "@/types/scheduling/PublicAppointmentApi"; @@ -35,7 +35,7 @@ export function AppointmentSuccess(props: { appointmentId: string }) { }); if (error) { - Notification.Error({ msg: t("appointment_not_found") }); + toast.error(t("appointment_not_found")); } const appointmentData = data?.results.find( diff --git a/src/pages/Appoinments/auth/PatientLogin.tsx b/src/pages/Appoinments/auth/PatientLogin.tsx index c43d8331fda..17d0406a23c 100644 --- a/src/pages/Appoinments/auth/PatientLogin.tsx +++ b/src/pages/Appoinments/auth/PatientLogin.tsx @@ -5,6 +5,7 @@ import { navigate } from "raviger"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { z } from "zod"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -31,7 +32,6 @@ import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormFi import useAppHistory from "@/hooks/useAppHistory"; import { useAuthContext } from "@/hooks/useAuthUser"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import request from "@/Utils/request/request"; @@ -103,9 +103,7 @@ export default function PatientLogin({ } }, onError: () => { - Notification.Error({ - msg: t("error_sending_otp"), - }); + toast.error(t("error_sending_otp")); }, }); @@ -153,9 +151,7 @@ export default function PatientLogin({ const errorData = error.cause as { errors: Array<{ otp: string }> }; const errorMessage = errorData?.errors?.[0]?.otp || t("error_verifying_otp"); - Notification.Error({ - msg: errorMessage, - }); + toast.error(errorMessage); }, }); diff --git a/src/pages/Facility/FacilityDetailsPage.tsx b/src/pages/Facility/FacilityDetailsPage.tsx index 7972699ee97..f97f36cc422 100644 --- a/src/pages/Facility/FacilityDetailsPage.tsx +++ b/src/pages/Facility/FacilityDetailsPage.tsx @@ -1,6 +1,7 @@ import { useQuery } from "@tanstack/react-query"; import { Link, navigate } from "raviger"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -15,7 +16,6 @@ import { UserAssignedModel } from "@/components/Users/models"; import useFilters from "@/hooks/useFilters"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import { PaginatedResponse, RequestResult } from "@/Utils/request/types"; @@ -53,7 +53,7 @@ export function FacilityDetailsPage({ id }: Props) { silent: true, }); if (response.res?.status !== 200) { - Notification.Error({ msg: "Error while fetching users data" }); + toast.error(t("error_fetching_users_data")); } return response; },