Custom Framework - Client

Make sure to check the qb.lua and esx.lua files for examples on how to implement the phone for your framework. They are always up to date with the latest changes.

Framework check

At the top of the file, add a check for Config.Framework. If it's not set to your framework, return to prevent it from loading.

if Config.Framework ~= "your-framework" then
    return
end

Wait for player to load

Next, you need to wait for the player to load. How this is done depends on your framework. Once the player's character has loaded, set loaded = true. This lets the phone know that your framework has loaded, and is ready to be used.

while not ESX.PlayerLoaded do
    Wait(500)
end
 
loaded = true

Framework events

The phone has a few common functions that can be used for framework events.

Player unload/switching character

Trigger LogOut() when the player unloads their character. This closes the phone, ends calls etc.

-- This is an example from the lb-phone qb.lua file
RegisterNetEvent("QBCore:Client:OnPlayerUnload", function()
    LogOut()
end)

When a character has been loaded, trigger FetchPhone() to load the phone.

-- This is an example from the lb-phone qb.lua file
RegisterNetEvent("QBCore:Client:OnPlayerLoaded", function()
    FetchPhone()
end)

Money change

When the player's money changes, you can trigger the wallet:setBalance NUI event to update the wallet balance.

SendReactMessage("wallet:setBalance", math.floor(bankBalance))

Inventory item removal

When an item is removed from the player's inventory, you can add a check if the player has a phone item. If not, close the phone.

-- This is an example from the lb-phone esx.lua file
RegisterNetEvent("esx:removeInventoryItem", function(item, count)
	-- Check if the config requires a phone item
    if not Config.Item.Require or Config.Item.Unique or item ~= Config.Item.Name or count > 0 then
        return
    end
 
	-- This wait allows various variables to update, fixing race conditions
    Wait(500)
 
    if not HasPhoneItem() then
		-- OnDeath closes the phone, ends calls etc.
        OnDeath()
    end
end)

Framework functions

You need to implement the following functions for the phone to work with your framework.

HasPhoneItem

Check if the player has the phone item in their inventory.

---@param number?: string # The phone number to check (if using unique phones)
---@return boolean
function HasPhoneItem(number)
    if not Config.Item.Require then
        return true
    end
 
    if Config.Item.Unique then
		-- HasPhoneNumber is a function defined in the unique phones file
        return HasPhoneNumber(number)
    end
 
	-- Implement your own check here
    return true
end

HasJob

Check if the player has one of various jobs

---@param jobs string[]
---@return boolean
function HasJob(jobs)
	-- Edit this to get the player's job
    local job = ESX.PlayerData.job.name
 
    for i = 1, #jobs do
        if jobs[i] == job then
            return true
        end
    end
 
    return false
end

Garage functions

ApplyVehicleMods

Apply vehicle mods to a vehicle

---@param vehicle number
---@param vehicleData table
function ApplyVehicleMods(vehicle, vehicleData) end

CreateFrameworkVehicle

Create a vehicle and apply mods

---@param vehicleData table
---@param coords vector3
---@return number? vehicle
function CreateFrameworkVehicle(vehicleData, coords)
	local model = LoadModel(vehicleData.model)
	local vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, 0.0, true, false)
 
	ApplyVehicleMods(vehicle, vehicleData)
 
	return vehicle
end

Companies/services functions

GetCompanyData

This function should callback or return the company data for the player's job.

---@param cb fun(companyData: table)
function GetCompanyData(cb)
    local companyData = {}
 
    return companyData
end

The company data should return the following:

  • job: string
  • jobLabel: string
  • isBoss: boolean
  • duty?: boolean - optional. Requires the ToggleDuty function to be implemented. For the toggle duty button to show, duty has to be true or false, not nil.

If the player is a boss, also return the following:

  • balance: number - The company's bank balance
  • employees: Employee[] - A list of employees
    • name: string
    • id: string - the player's identifier
    • gradeLabel: string
    • grade: string
    • canInteract: boolean - Whether the player can interact with this employee (fire, promote etc.)
  • grades: Grade[]
    • label: string
    • grade: any

DepositMoney

Deposit money into the company's bank account. Return or callback the updated bank balance.

---@param amount number
---@param cb fun(amount: number)
function DepositMoney(amount, cb)
    -- Implement your deposit function here
    return newBalance
end

WithdrawMoney

Withdraw money from the company's bank account. Return or callback the updated bank balance.

---@param amount number
---@param cb fun(amount: number)
function WithdrawMoney(amount, cb)
    -- Implement your withdraw function here
    return newBalance
end

HireEmployee

Hire an employee. Return or callback the player data of the new employee (name & id).

---@param source number
---@param cb fun(employee: Employee)
function HireEmployee(source, cb)
    -- Implement your hire function here
    return { name = "John Doe", id = "license:1234567890" }
end

FireEmployee

Fire an employee. Return or callback boolean

---@param id string
---@param cb fun(success: boolean)
function FireEmployee(id, cb)
    -- Implement your fire function here
    return true
end

SetGrade

Promote/demote an employee. Return or callback boolean

---@param id string
---@param grade string
---@param cb fun(success: boolean)
function SetGrade(id, grade, cb)
    -- Implement your set grade function here
    return true
end

ToggleDuty

Optional. Toggle the player's duty status. You do not need to return anything.

function ToggleDuty()
    -- Implement your duty toggle function here
    TriggerServerEvent("QBCore:ToggleDuty")
end