From 0a194fee7c4dbd12401e75e9949817bcc8564da8 Mon Sep 17 00:00:00 2001
From: Tony <97451137+TonybynMp4@users.noreply.github.com>
Date: Sat, 30 Mar 2024 22:49:59 +0100
Subject: [PATCH] feat: transfervehicle using phone notifications & small fixes

---
 client/main.lua |  42 +++++++++---
 locales/en.json | 165 ++++++++++++++++++++++++------------------------
 locales/fr.json |   3 +-
 server/main.lua |   7 +-
 4 files changed, 124 insertions(+), 93 deletions(-)

diff --git a/client/main.lua b/client/main.lua
index 2a7916f..91c075c 100644
--- a/client/main.lua
+++ b/client/main.lua
@@ -620,15 +620,41 @@ RegisterNetEvent('qbx_vehicleshop:client:buyShowroomVehicle', function(vehicle,
     TriggerServerEvent('qb-vehicletuning:server:SaveVehicleProps', props)
 end)
 
-lib.callback.register('qbx_vehicleshop:client:confirmTrade', function(vehicle, sellAmount)
-    local input = lib.inputDialog(locale('general.transfervehicle_confirm', VEHICLES_HASH[vehicle].brand, VEHICLES_HASH[vehicle].name, lib.math.groupdigits(sellAmount) or 0),{
-        {
-            type = 'checkbox',
-            label = 'Confirm'
-        },
+local function confirmTrade(confirmationText)
+    local accepted
+    exports.npwd:createSystemNotification({
+        uniqId = "vehicleShop:confirmTrade",
+        content = confirmationText,
+        secondary = "Confirm Trade",
+        keepOpen = true,
+        duration = 10000,
+        controls = true,
+        onConfirm = function()
+            accepted = true
+        end,
+        onCancel = function()
+            accepted = false
+        end,
     })
-    if not input then return false end
-    if input[1] == true then return true end
+    while accepted == nil do Wait(100) end
+    return accepted
+end
+
+lib.callback.register('qbx_vehicleshop:client:confirmTrade', function(vehicle, sellAmount)
+    local confirmationText = locale('general.transfervehicle_confirm', VEHICLES_HASH[vehicle].brand, VEHICLES_HASH[vehicle].name, lib.math.groupdigits(sellAmount) or 0)
+    if GetResourceState('npwd') ~= 'started' then
+        local input = lib.inputDialog(confirmationText, {
+            {
+                type = 'checkbox',
+                label = 'Confirm'
+            },
+        })
+        return input?[1]
+    end
+
+    local p = promise:new()
+    p:resolve(confirmTrade(confirmationText))
+    return Citizen.Await(p)
 end)
 
 --- Thread to create blips
diff --git a/locales/en.json b/locales/en.json
index 7509161..b321a96 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -1,82 +1,83 @@
-{
-    "error": {
-        "testdrive_alreadyin": "Already in test drive",
-        "testdrive_return": "This is not your test drive vehicle",
-        "Invalid_ID": "Invalid Player Id Supplied",
-        "playertoofar": "This player is not close enough",
-        "notenoughmoney": "Not enough money",
-        "minimumallowed": "Minimum payment allowed is $",
-        "overpaid": "You overpaid",
-        "alreadypaid": "Vehicle is already paid off",
-        "notworth": "Vehicle is not worth that much",
-        "downtoosmall": "Down payment too small",
-        "exceededmax": "Exceeded maximum payment amount",
-        "repossessed": "Your vehicle with plate %s has been repossessed",
-        "buyerinfo": "Couldn't get buyer info",
-        "notinveh": "You must be in the vehicle you want to transfer",
-        "vehinfo": "Couldn't get vehicle info",
-        "notown": "You don't own this vehicle",
-        "buyertoopoor": "The buyer doesn't have enough money",
-        "nofinanced": "You don't have any financed vehicles",
-        "financed": "This vehicle is financed",
-        "buyerdeclined": "The player declined the transaction",
-        "sale_timeout": "Wait a while before trading your vehicle"
-    },
-    "success": {
-        "purchased": "Congratulations on your purchase!",
-        "earned_commission": "You earned $ %s in commission",
-        "gifted": "You gifted your vehicle",
-        "received_gift": "You were gifted a vehicle",
-        "soldfor": "You sold your vehicle for $",
-        "boughtfor": "You bought a vehicle for $"
-    },
-    "menus": {
-        "vehHeader_header": "Vehicle Options",
-        "vehHeader_txt": "Interact with the current vehicle",
-        "financed_header": "Financed Vehicles",
-        "finance_txt": "Browse your owned vehicles",
-        "returnTestDrive_header": "Finish Test Drive",
-        "categories_header": "Categories",
-        "goback_header": "Go Back",
-        "veh_price": "Price: $",
-        "veh_platetxt": "Plate: ",
-        "veh_finance": "Vehicle Payment",
-        "veh_finance_balance": "Total Balance Remaining",
-        "veh_finance_currency": "$",
-        "veh_finance_total": "Total Payments Remaining",
-        "veh_finance_reccuring": "Recurring Payment Amount",
-        "veh_finance_pay": "Make a payment",
-        "veh_finance_payoff": "Payoff vehicle",
-        "veh_finance_payment": "Payment Amount ($)",
-        "submit_text": "Submit",
-        "test_header": "Test Drive",
-        "finance_header": "Finance Vehicle",
-        "owned_vehicles_header": "Owned Vehicles",
-        "swap_header": "Swap Vehicle",
-        "swap_txt": "Change currently selected vehicle",
-        "financesubmit_downpayment": "Down Payment Amount - Min ",
-        "financesubmit_totalpayment": "Total Payments - Max ",
-        "freeuse_test_txt": "Test drive currently selected vehicle",
-        "freeuse_buy_header": "Buy Vehicle",
-        "freeuse_buy_txt": "Purchase currently selected vehicle",
-        "freeuse_finance_txt": "Finance currently selected vehicle",
-        "managed_test_txt": "Allow player for test drive",
-        "managed_sell_header": "Sell Vehicle",
-        "managed_sell_txt": "Sell vehicle to Player",
-        "managed_finance_txt": "Finance vehicle to Player",
-        "submit_ID": "Server ID (#)",
-        "keypress_showFinanceMenu": "[E] Open Finance Menu",
-        "keypress_vehicleViewMenu": "[E] View Vehicle"
-    },
-    "general": {
-        "testdrive_timer": "Test Drive Time Remaining: ",
-        "vehinteraction": "Vehicle Interaction",
-        "testdrive_timenoti": "You have %s minutes remaining",
-        "testdrive_complete": "Vehicle test drive complete",
-        "paymentduein": "Your vehicle payment is due within %s minutes",
-        "command_transfervehicle": "Gift or sell your vehicle",
-        "command_transfervehicle_help": "ID of buyer",
-        "command_transfervehicle_amount": "Sell amount (optional)",
-        "transfervehicle_confirm": "Confirm trade of %s %s for $ %s"
-    }
-}
+{
+    "error": {
+        "testdrive_alreadyin": "Already in test drive",
+        "testdrive_return": "This is not your test drive vehicle",
+        "Invalid_ID": "Invalid Player Id Supplied",
+        "playertoofar": "This player is not close enough",
+        "notenoughmoney": "Not enough money",
+        "minimumallowed": "Minimum payment allowed is $",
+        "overpaid": "You overpaid",
+        "alreadypaid": "Vehicle is already paid off",
+        "notworth": "Vehicle is not worth that much",
+        "downtoosmall": "Down payment too small",
+        "exceededmax": "Exceeded maximum payment amount",
+        "repossessed": "Your vehicle with plate %s has been repossessed",
+        "buyerinfo": "Couldn't get buyer info",
+        "notinveh": "You must be in the vehicle you want to transfer",
+        "vehinfo": "Couldn't get vehicle info",
+        "notown": "You don't own this vehicle",
+        "buyertoopoor": "The buyer doesn't have enough money",
+        "nofinanced": "You don't have any financed vehicles",
+        "financed": "This vehicle is financed",
+        "buyerdeclined": "The player declined the transaction",
+        "selftransfer": "You can't transfer to yourself",
+        "sale_timeout": "Wait a while before trading your vehicle"
+    },
+    "success": {
+        "purchased": "Congratulations on your purchase!",
+        "earned_commission": "You earned $ %s in commission",
+        "gifted": "You gifted your vehicle",
+        "received_gift": "You were gifted a vehicle",
+        "soldfor": "You sold your vehicle for $",
+        "boughtfor": "You bought a vehicle for $"
+    },
+    "menus": {
+        "vehHeader_header": "Vehicle Options",
+        "vehHeader_txt": "Interact with the current vehicle",
+        "financed_header": "Financed Vehicles",
+        "finance_txt": "Browse your owned vehicles",
+        "returnTestDrive_header": "Finish Test Drive",
+        "categories_header": "Categories",
+        "goback_header": "Go Back",
+        "veh_price": "Price: $",
+        "veh_platetxt": "Plate: ",
+        "veh_finance": "Vehicle Payment",
+        "veh_finance_balance": "Total Balance Remaining",
+        "veh_finance_currency": "$",
+        "veh_finance_total": "Total Payments Remaining",
+        "veh_finance_reccuring": "Recurring Payment Amount",
+        "veh_finance_pay": "Make a payment",
+        "veh_finance_payoff": "Payoff vehicle",
+        "veh_finance_payment": "Payment Amount ($)",
+        "submit_text": "Submit",
+        "test_header": "Test Drive",
+        "finance_header": "Finance Vehicle",
+        "owned_vehicles_header": "Owned Vehicles",
+        "swap_header": "Swap Vehicle",
+        "swap_txt": "Change currently selected vehicle",
+        "financesubmit_downpayment": "Down Payment Amount - Min ",
+        "financesubmit_totalpayment": "Total Payments - Max ",
+        "freeuse_test_txt": "Test drive currently selected vehicle",
+        "freeuse_buy_header": "Buy Vehicle",
+        "freeuse_buy_txt": "Purchase currently selected vehicle",
+        "freeuse_finance_txt": "Finance currently selected vehicle",
+        "managed_test_txt": "Allow player for test drive",
+        "managed_sell_header": "Sell Vehicle",
+        "managed_sell_txt": "Sell vehicle to Player",
+        "managed_finance_txt": "Finance vehicle to Player",
+        "submit_ID": "Server ID (#)",
+        "keypress_showFinanceMenu": "[E] Open Finance Menu",
+        "keypress_vehicleViewMenu": "[E] View Vehicle"
+    },
+    "general": {
+        "testdrive_timer": "Test Drive Time Remaining: ",
+        "vehinteraction": "Vehicle Interaction",
+        "testdrive_timenoti": "You have %s minutes remaining",
+        "testdrive_complete": "Vehicle test drive complete",
+        "paymentduein": "Your vehicle payment is due within %s minutes",
+        "command_transfervehicle": "Gift or sell your vehicle",
+        "command_transfervehicle_help": "ID of buyer",
+        "command_transfervehicle_amount": "Sell amount (optional)",
+        "transfervehicle_confirm": "Confirm trade of %s %s for $ %s"
+    }
+}
diff --git a/locales/fr.json b/locales/fr.json
index 6d76ebf..ed9db9b 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -20,8 +20,9 @@
         "nofinanced": "Vous n'avez aucun véhicule financés",
         "financed": "Ce véhicule est financé",
         "buyerdeclined": "The player declined the transaction",
+        "selftransfer": "Vous ne pouvez pas transférer à vous-même",
         "sale_timeout": "Wait a while before trading your vehicle"
-},
+    },
     "success": {
         "purchased": "Félicitations sur votre achat!",
         "earned_commission": "Vous avez gagné $ %s de commission",
diff --git a/server/main.lua b/server/main.lua
index 79aec26..81fe3bc 100644
--- a/server/main.lua
+++ b/server/main.lua
@@ -433,6 +433,9 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl
     local src = source
     local buyerId = args.id
     local sellAmount = args.amount or 0
+    if src == buyerId then
+        return exports.qbx_core:Notify(src, locale('error.selftransfer'), 'error')
+    end
     if saleTimeout[src] then
         return exports.qbx_core:Notify(src, locale('error.sale_timeout'), 'error')
     end
@@ -451,7 +454,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl
         return exports.qbx_core:Notify(src, locale('error.notinveh'), 'error')
     end
 
-    local plate = string.trim(GetVehicleNumberPlateText(vehicle))
+    local plate = qbx.string.trim(GetVehicleNumberPlateText(vehicle))
     if not plate then
         return exports.qbx_core:Notify(src, locale('error.vehinfo'), 'error')
     end
@@ -461,7 +464,7 @@ lib.addCommand('transfervehicle', {help = locale('general.command_transfervehicl
     local row = FetchVehicleEntityByPlate(plate)
     if config.finance.preventSelling then
         local financeRow = FetchFinancedVehicleEntityById(row.id)
-        if financeRow.balance > 0 then
+        if financeRow and financeRow.balance > 0 then
             return exports.qbx_core:Notify(src, locale('error.financed'), 'error')
         end
     end