forked from Simnation/Main
ed
This commit is contained in:
parent
30bef7f1a5
commit
9e0a584816
52 changed files with 11959 additions and 0 deletions
459
resources/[tools]/ps-banking/LICENSE
Normal file
459
resources/[tools]/ps-banking/LICENSE
Normal file
|
@ -0,0 +1,459 @@
|
|||
Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
||||
|
||||
https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
This is a human-readable summary of (and not a substitute for) the license. Disclaimer.
|
||||
|
||||
You are free to:
|
||||
|
||||
Share — copy and redistribute the material in any medium or format
|
||||
Adapt — remix, transform, and build upon the material
|
||||
|
||||
The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||||
|
||||
Under the following terms:
|
||||
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||
|
||||
NonCommercial — You may not use the material for commercial purposes.
|
||||
|
||||
ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||
|
||||
Notices:
|
||||
You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation.
|
||||
No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material.
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-NC-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
l. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
m. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
n. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material for
|
||||
NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
54
resources/[tools]/ps-banking/README.md
Normal file
54
resources/[tools]/ps-banking/README.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
# ps-banking
|
||||
Compatible with QBCore and ESX.
|
||||
|
||||
# Depedency
|
||||
1. [qb-core](https://github.com/qbcore-framework/qb-core) or [ESX](https://github.com/esx-framework)
|
||||
2. [ox_lib](https://github.com/overextended/ox_lib)
|
||||
|
||||
# Installation
|
||||
* Download release files.
|
||||
* Drag and drop resource into your server files.
|
||||
* Start resource through server.cfg.
|
||||
* Add the ps-banking sql file to your database.
|
||||
* Restart your server.
|
||||
|
||||
## Exports
|
||||
|
||||
### Create Bill
|
||||
```bash
|
||||
# Creates a bill invoice in the bank
|
||||
exports["ps-banking"]:createBill({
|
||||
identifier = "HVZ84591", -- citizen id
|
||||
description = "Utility Bill",
|
||||
type = "Expense",
|
||||
amount = 150.00,
|
||||
})
|
||||
```
|
||||
|
||||
# Features
|
||||
### Overview Tab:
|
||||
Includes all essential features such as managing your bills, withdrawing all money, depositing cash, transferring money weekly via Simmy, viewing the latest transactions, and handling unpaid invoices.
|
||||

|
||||
|
||||
### Bills
|
||||
Enables you to send and receive bills.
|
||||

|
||||
|
||||
### History
|
||||
Displays a history of all transactions with options to delete specific transactions.
|
||||

|
||||
|
||||
### Stats and Reports
|
||||
Provides a summary of all transactions made, including total amounts, current balance, and transaction trends by date and amount.
|
||||

|
||||
|
||||
### Accounts
|
||||
Allows you to create, add, or remove accounts, rename accounts, and perform deposits or withdrawals from specific accounts.
|
||||

|
||||
|
||||
### ATM Access
|
||||
Deposit and withdraw from ATMs.
|
||||

|
||||
|
||||
# Credits
|
||||
* [BachPB](https://github.com/BachPB)
|
363
resources/[tools]/ps-banking/client/main.lua
Normal file
363
resources/[tools]/ps-banking/client/main.lua
Normal file
|
@ -0,0 +1,363 @@
|
|||
local framework = nil
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getLocales", function(_, cb)
|
||||
cb(lib.getLocales())
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:hideUI", function(_, cb)
|
||||
SetNuiFocus(false, false)
|
||||
cb({})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:phoneOption", function(_, cb)
|
||||
cb(Config.LBPhone)
|
||||
end)
|
||||
|
||||
-- Banks
|
||||
RegisterNetEvent('ps-banking:client:open:bank')
|
||||
AddEventHandler('ps-banking:client:open:bank', function()
|
||||
Citizen.Wait(100)
|
||||
SendNUIMessage({
|
||||
action = "openBank",
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end)
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
local zoneId = 1
|
||||
for _, location in pairs(Config.BankLocations.Coords) do
|
||||
local zoneName = "bank_" .. zoneId
|
||||
if Config.TargetSystem == "interact" then
|
||||
exports.interact:AddInteraction({
|
||||
coords = vec3(location.x, location.y, location.z),
|
||||
distance = 2.5,
|
||||
interactDst = 2.5,
|
||||
id = locale("openBank").."interact",
|
||||
name = locale("openBank").."interact:name",
|
||||
options = {
|
||||
{
|
||||
label = 'Access Bank',
|
||||
action = function()
|
||||
SendNUIMessage({
|
||||
action = "openBank",
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end,
|
||||
},
|
||||
}
|
||||
})
|
||||
elseif Config.TargetSystem == "ox_target" then
|
||||
exports.ox_target:addBoxZone({
|
||||
name = zoneName,
|
||||
coords = vector3(location.x, location.y, location.z),
|
||||
size = vec3(2, 2, 2),
|
||||
options = {
|
||||
{
|
||||
event = "ps-banking:client:open:bank",
|
||||
icon = "fas fa-credit-card",
|
||||
label = locale("openBank"),
|
||||
},
|
||||
},
|
||||
})
|
||||
else
|
||||
exports["qb-target"]:AddBoxZone(zoneName, vector3(location.x, location.y, location.z), 1.5, 1.6, {
|
||||
name = zoneName,
|
||||
heading = 0.0,
|
||||
debugPoly = false,
|
||||
minZ = location.z - 1,
|
||||
maxZ = location.z + 1,
|
||||
}, {
|
||||
options = {
|
||||
{
|
||||
icon = "fas fa-credit-card",
|
||||
label = locale("openBank"),
|
||||
action = function()
|
||||
SendNUIMessage({
|
||||
action = "openBank",
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end,
|
||||
},
|
||||
},
|
||||
distance = 2.5,
|
||||
})
|
||||
zoneId = zoneId + 1
|
||||
end
|
||||
|
||||
for i = 1, #Config.BankLocations.Coords do
|
||||
local blip = AddBlipForCoord(vector3(Config.BankLocations.Coords[i].x, Config.BankLocations.Coords[i].y,
|
||||
Config.BankLocations.Coords[i].z))
|
||||
SetBlipSprite(blip, Config.BankLocations.Blips.sprite)
|
||||
SetBlipDisplay(blip, 4)
|
||||
SetBlipScale(blip, Config.BankLocations.Blips.scale)
|
||||
SetBlipColour(blip, Config.BankLocations.Blips.color)
|
||||
SetBlipAsShortRange(blip, true)
|
||||
BeginTextCommandSetBlipName("STRING")
|
||||
AddTextComponentSubstringPlayerName(Config.BankLocations.Blips.name)
|
||||
EndTextCommandSetBlipName(blip)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ATMs
|
||||
RegisterNetEvent('ps-banking:client:open:atm')
|
||||
AddEventHandler('ps-banking:client:open:atm', function()
|
||||
Citizen.Wait(100)
|
||||
ATM_Animation()
|
||||
SendNUIMessage({
|
||||
action = "openATM",
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end)
|
||||
|
||||
function ATM_Animation()
|
||||
lib.playAnim(cache.ped, Config.ATM_Animation.dict, Config.ATM_Animation.name, 8.0, -8.0, -1, Config.ATM_Animation.flag, 0, false, 0, false)
|
||||
Wait(GetAnimDuration(Config.ATM_Animation.dict,Config.ATM_Animation.name) * 1000)
|
||||
ClearPedTasks(cache.ped)
|
||||
end
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
if Config.TargetSystem == "interact" then
|
||||
for _, ATM_Models in ipairs(Config.ATM_Models) do
|
||||
exports.interact:AddModelInteraction({
|
||||
model = ATM_Models,
|
||||
offset = vec3(0.0, 0.0, 1.0),
|
||||
name = locale("openATM") .. "interact:name",
|
||||
id = locale("openATM") .. "interact",
|
||||
distance = 2.5,
|
||||
interactDst = 2.5,
|
||||
options = {
|
||||
{
|
||||
label = locale("openATM"),
|
||||
event = "ps-banking:client:open:atm",
|
||||
},
|
||||
}
|
||||
})
|
||||
end
|
||||
elseif Config.TargetSystem == "ox_target" then
|
||||
for _, ATM_Models in ipairs(Config.ATM_Models) do
|
||||
exports.ox_target:addModel(ATM_Models, {
|
||||
icon = "fas fa-solid fa-money-bills",
|
||||
label = locale("openATM"),
|
||||
event = "ps-banking:client:open:atm",
|
||||
canInteract = function(_, distance)
|
||||
return distance < 2.5
|
||||
end,
|
||||
})
|
||||
end
|
||||
else
|
||||
exports["qb-target"]:AddTargetModel(Config.ATM_Models, {
|
||||
options = {
|
||||
{
|
||||
icon = "fas fa-solid fa-money-bills",
|
||||
label = locale("openATM"),
|
||||
action = function()
|
||||
ATM_Animation()
|
||||
SendNUIMessage({
|
||||
action = "openATM",
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end,
|
||||
},
|
||||
},
|
||||
distance = 2.5,
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
if GetResourceState("es_extended") == "started" then
|
||||
framework = "ESX"
|
||||
ESX = exports["es_extended"]:getSharedObject()
|
||||
elseif GetResourceState("qb-core") == "started" then
|
||||
framework = "QBCore"
|
||||
QBCore = exports["qb-core"]:GetCoreObject()
|
||||
else
|
||||
return error(locale("no_framework_found"))
|
||||
end
|
||||
|
||||
local function getPlayerAccounts()
|
||||
local accounts = {}
|
||||
if framework == "ESX" then
|
||||
accounts = ESX.GetPlayerData().accounts
|
||||
elseif framework == "QBCore" then
|
||||
accounts = QBCore.Functions.GetPlayerData().money
|
||||
end
|
||||
return accounts
|
||||
end
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getBills", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:getBills", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:payBill", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:payBill", false, data.id)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getHistory", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:getHistory", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:deleteHistory", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:deleteHistory", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:payAllBills", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:payAllBills", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getWeeklySummary", function(data, cb)
|
||||
local summary = lib.callback.await("ps-banking:server:getWeeklySummary", false)
|
||||
cb(summary)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:transferMoney", function(data, cb)
|
||||
local success, message = lib.callback.await("ps-banking:server:transferMoney", false, data)
|
||||
cb({
|
||||
success = success,
|
||||
message = message,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getTransactionStats", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:getTransactionStats", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
if framework == "ESX" then
|
||||
RegisterNetEvent("esx:setAccountMoney", function(account)
|
||||
local moneyData = {}
|
||||
for k, v in pairs(getPlayerAccounts()) do
|
||||
table.insert(moneyData, {
|
||||
amount = v.money,
|
||||
name = v.name == "money" and "cash" or v.name,
|
||||
})
|
||||
end
|
||||
Wait(50)
|
||||
TriggerServerEvent("ps-banking:server:logClient", account, moneyData)
|
||||
end)
|
||||
elseif framework == "QBCore" then
|
||||
RegisterNetEvent("QBCore:Client:OnMoneyChange", function(moneyType, amount)
|
||||
local moneyData = {}
|
||||
for k, v in pairs(getPlayerAccounts()) do
|
||||
table.insert(moneyData, {
|
||||
name = k,
|
||||
amount = v,
|
||||
})
|
||||
end
|
||||
Wait(50)
|
||||
TriggerServerEvent("ps-banking:server:logClient", {
|
||||
name = "bank",
|
||||
moneyType = moneyType,
|
||||
amount = amount,
|
||||
}, moneyData)
|
||||
end)
|
||||
end
|
||||
|
||||
RegisterNUICallback("ps-banking:client:createNewAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:createNewAccount", false, data.newAccount)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getUser", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:getUser", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getAccounts", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:getAccounts", false)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:deleteAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:deleteAccount", false, data.accountId)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:withdrawFromAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:withdrawFromAccount", false, data.accountId, data.amount)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:depositToAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:depositToAccount", false, data.accountId, data.amount)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:addUserToAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:addUserToAccount", false, data.accountId, data.userId)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:removeUserFromAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:removeUserFromAccount", false, data.accountId, data.user)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:renameAccount", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:renameAccount", false, data.id, data.newName)
|
||||
cb({
|
||||
success = success,
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:copyAccountNumber", function(data, cb)
|
||||
lib.setClipboard(data.accountNumber)
|
||||
cb(true)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:ATMwithdraw", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:ATMwithdraw", false, data.amount)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:ATMdeposit", function(data, cb)
|
||||
local success = lib.callback.await("ps-banking:server:ATMdeposit", false, data.amount)
|
||||
cb(success)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getMoneyTypes", function(data, cb)
|
||||
local moneyData = {}
|
||||
|
||||
if framework == "ESX" then
|
||||
for k, v in pairs(getPlayerAccounts()) do
|
||||
table.insert(moneyData, {
|
||||
amount = v.money,
|
||||
name = v.name == "money" and "cash" or v.name,
|
||||
})
|
||||
end
|
||||
elseif framework == "QBCore" then
|
||||
local PlayerData = QBCore.Functions.GetPlayerData()
|
||||
for k, v in pairs(PlayerData.money) do
|
||||
table.insert(moneyData, {
|
||||
amount = v,
|
||||
name = k,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
--print(json.encode(moneyData))
|
||||
cb(moneyData)
|
||||
end)
|
||||
|
||||
RegisterNUICallback("ps-banking:client:getAmountPresets", function(_, cb)
|
||||
cb(json.encode({
|
||||
withdrawAmounts = Config.PresetATM_Amounts.Amounts,
|
||||
depositAmounts = Config.PresetATM_Amounts.Amounts,
|
||||
grid = Config.PresetATM_Amounts.Grid,
|
||||
}))
|
||||
end)
|
51
resources/[tools]/ps-banking/config.lua
Normal file
51
resources/[tools]/ps-banking/config.lua
Normal file
|
@ -0,0 +1,51 @@
|
|||
lib.locale()
|
||||
Config = {}
|
||||
Config.LBPhone = false -- Does your server use lb-phone?
|
||||
Config.TargetSystem = "qb-target" -- Change to your target script like ox_target, qb-target, Or use devyn's interact.
|
||||
|
||||
Config.Currency = {
|
||||
lang = "de", -- da-DK
|
||||
currency = "USD", -- DKK
|
||||
}
|
||||
|
||||
Config.BankLocations = {
|
||||
Coords = {
|
||||
vector3(149.05, -1041.3, 29.37),
|
||||
vector3(313.32, -280.03, 54.17),
|
||||
vector3(-351.94, -50.72, 49.04),
|
||||
vector3(-1212.68, -331.83, 37.78),
|
||||
vector3(-2961.67, 482.31, 15.7),
|
||||
vector3(1175.64, 2707.71, 38.09),
|
||||
vector3(247.65, 223.87, 106.29),
|
||||
vector3(-111.98, 6470.56, 31.63),
|
||||
},
|
||||
Blips = {
|
||||
name = "Bank",
|
||||
sprite = 108,
|
||||
color = 2,
|
||||
scale = 0.55,
|
||||
},
|
||||
}
|
||||
|
||||
-- ATM stuff
|
||||
Config.PresetATM_Amounts = { -- The preset amounts
|
||||
Amounts = {
|
||||
2000,
|
||||
5000,
|
||||
10000,
|
||||
},
|
||||
Grid = 3, -- How many there should be on each
|
||||
}
|
||||
|
||||
Config.ATM_Animation = { -- Anim when opening ATM
|
||||
dict = "anim@amb@prop_human_atm@interior@male@enter",
|
||||
name = "enter",
|
||||
flag = 49,
|
||||
}
|
||||
|
||||
Config.ATM_Models = {
|
||||
"prop_atm_01",
|
||||
"prop_atm_02",
|
||||
"prop_atm_03",
|
||||
"prop_fleeca_atm",
|
||||
}
|
35
resources/[tools]/ps-banking/fxmanifest.lua
Normal file
35
resources/[tools]/ps-banking/fxmanifest.lua
Normal file
|
@ -0,0 +1,35 @@
|
|||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
name 'ps-banking'
|
||||
author 'Project Sloth'
|
||||
version '1.0.4'
|
||||
|
||||
ui_page 'html/index.html'
|
||||
-- ui_page 'http://localhost:5173'
|
||||
|
||||
shared_scripts {
|
||||
'@ox_lib/init.lua',
|
||||
'config.lua',
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'client/**/*',
|
||||
}
|
||||
|
||||
server_scripts {
|
||||
'@oxmysql/lib/MySQL.lua',
|
||||
'server/**/*',
|
||||
}
|
||||
|
||||
files {
|
||||
'html/**/*',
|
||||
'locales/**/*',
|
||||
}
|
||||
|
||||
dependencies {
|
||||
'ox_lib',
|
||||
'oxmysql'
|
||||
}
|
||||
|
||||
lua54 'yes'
|
1
resources/[tools]/ps-banking/html/index.css
Normal file
1
resources/[tools]/ps-banking/html/index.css
Normal file
File diff suppressed because one or more lines are too long
50
resources/[tools]/ps-banking/html/index.html
Normal file
50
resources/[tools]/ps-banking/html/index.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bach Banking</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/all.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-duotone-solid.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-thin.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-solid.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-regular.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-light.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" />
|
||||
<script type="module" crossorigin src="./index.js"></script>
|
||||
<link rel="stylesheet" href="./index.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<style>
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
::-webkit-outer-spin-button,
|
||||
::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
24
resources/[tools]/ps-banking/html/index.js
Normal file
24
resources/[tools]/ps-banking/html/index.js
Normal file
File diff suppressed because one or more lines are too long
139
resources/[tools]/ps-banking/locales/cs.json
Normal file
139
resources/[tools]/ps-banking/locales/cs.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "Bankomat",
|
||||
"cash": "Hotovost",
|
||||
"bank_balance": "Stav na účtu",
|
||||
"deposit_amount": "Částka k vkladu",
|
||||
"withdraw_amount": "Částka k výběru",
|
||||
"submit": "Odeslat",
|
||||
"close": "Zavřít",
|
||||
"overview": "Přehled",
|
||||
"bills": "Faktury",
|
||||
"history": "Historie",
|
||||
"withdraw": "Vybrat",
|
||||
"deposit": "Vložit",
|
||||
"stats": "Statistiky",
|
||||
"transactions": "Transakce",
|
||||
"transaction": "Transakce",
|
||||
"total": "Celkem",
|
||||
"search_transactions": "Hledat transakce...",
|
||||
"description": "Popis",
|
||||
"type": "Typ",
|
||||
"time_ago": "Před",
|
||||
"amount": "Částka",
|
||||
"date": "Datum",
|
||||
"pay_invoice": "Zaplatit fakturu",
|
||||
"payment_completed": "Platba dokončena",
|
||||
"from": "Od",
|
||||
"delete_all_transactions": "Smazat všechny transakce",
|
||||
"are_you_sure": "Jsi si jistý?",
|
||||
"delete_confirmation": "Opravdu chceš smazat všechny své transakce? (Udělěj to pouze, pokud se menu zpomaluje!)",
|
||||
"cancel": "Zrušit",
|
||||
"confirm": "Potvrdit",
|
||||
"history_empty": "Tvoje historie je prázdná",
|
||||
"all_history_deleted": "Všechny tvé historie byly smazány",
|
||||
"error": "Chyba",
|
||||
"success": "Úspěch",
|
||||
"new_cash": "Nová hotovost",
|
||||
"withdraw_success": "Výběr úspěšný",
|
||||
"withdraw_error": "Na tvém účtu není dostatek peněz",
|
||||
"withdraw_button": "VYBRAT",
|
||||
"new_bank": "Nový stav účtu",
|
||||
"current_cash": "Aktuální hotovost",
|
||||
"deposit_success": "Vklad úspěšný",
|
||||
"deposit_error": "Nemáš dostatek hotovosti",
|
||||
"deposit_button": "VLOŽIT",
|
||||
"total_balance": "Celkový zůstatek",
|
||||
"quick_actions": "Rychlé akce",
|
||||
"transfer_money": "Převést peníze",
|
||||
"easy_transfer": "Snadno převést peníze lidem",
|
||||
"transfer": "Převést",
|
||||
"pay_bills": "Zaplatit faktury",
|
||||
"pay_pending_bills": "Rychle zaplatit své neuhrazené faktury",
|
||||
"pay": "Zaplatit",
|
||||
"withdraw_all_money": "Vybrat všechny peníze",
|
||||
"withdraw_all_from_account": "Vybrat všechny peníze z účtu",
|
||||
"deposit_cash": "Vložit hotovost",
|
||||
"deposit_all_cash": "Vložit všechnu hotovost na účet",
|
||||
"weekly_summary": "Týdenní přehled",
|
||||
"income": "Příjem",
|
||||
"expenses": "Výdaje",
|
||||
"report": "Zpráva",
|
||||
"latest_transactions": "Poslední transakce",
|
||||
"see_all": "ZOBRAZIT VŠE",
|
||||
"unpaid_bills": "Nezaplacené faktury",
|
||||
"no_unpaid_bills": "Žádné nezaplacené faktury",
|
||||
"confirm_pay_all_bills": "Opravdu chceš zaplatit všechny své faktury?",
|
||||
"pay_all_bills": "Zaplatit všechny faktury",
|
||||
"pay_all_bills_success": "Všechny tvoje faktury byly zaplaceny!",
|
||||
"pay_all_bills_error": "Nemáš žádné faktury",
|
||||
"payment_method": "Způsob platby",
|
||||
"phone_number": "Telefonní číslo",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID nebo telefonní číslo",
|
||||
"no_cash_on_you": "Nemáš u sebe žádnou hotovost",
|
||||
"deposit_all_success": "Všechny tvoje peníze byly vloženy",
|
||||
"no_money_on_account": "Tvůj účet je prázdný",
|
||||
"withdraw_all_success": "Vybral jsi všechny peníze z účtu",
|
||||
"invoices": "Faktury",
|
||||
"statistics_reports": "Statistiky a zprávy",
|
||||
"balance_trend": "Trendy zůstatku",
|
||||
"balance": "Zůstatek",
|
||||
"used": "Použito",
|
||||
"month": "Měsíc",
|
||||
"balance_dkk": "Zůstatek",
|
||||
"withdrawn": "Vybral jsi",
|
||||
"deposited": "Vložil jsi",
|
||||
"no_transactions": "Žádné nedávné transakce",
|
||||
"transactions_trend": "Trendy transakcí",
|
||||
"total_transactions": "Celkem transakcí",
|
||||
"accounts": "Účty",
|
||||
"account_number_copied": "Číslo účtu zkopírováno do schránky",
|
||||
"new_user_to_account": "Nový uživatel na účet",
|
||||
"server_id": "ID serveru",
|
||||
"add_user": "Přidat uživatele",
|
||||
"new_account_name": "Nový název účtu",
|
||||
"new_name": "Nový název",
|
||||
"rename": "Přejmenovat",
|
||||
"create_new_account": "Vytvořit nový účet",
|
||||
"account_holder": "Majitel účtu",
|
||||
"initial_balance": "Počáteční zůstatek",
|
||||
"create": "Vytvořit",
|
||||
"delete_account": "Smazat účet",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Opravdu chceš smazat tento účet?",
|
||||
"delete": "Smazat",
|
||||
"remove_user_from_account": "Odebrat uživatele z účtu",
|
||||
"select_user": "Vyber uživatele",
|
||||
"remove": "Odebrat",
|
||||
"withdraw_from_account": "Vybrat z účtu",
|
||||
"deposit_to_account": "Vložit na účet",
|
||||
"removed_successfully": "úspěšně odstraněn",
|
||||
"select_account_and_user": "Prosím vyber účet a uživatele",
|
||||
"account_deleted_successfully": "Účet úspěšně smazán",
|
||||
"new_account_created_successfully": "Nový účet úspěšně vytvořen",
|
||||
"withdrew": "Vybral jsi",
|
||||
"successfully": "úspěšně",
|
||||
"select_valid_account_and_amount": "Prosím vyber platný účet a částku",
|
||||
"openBank": "Přístup do banky",
|
||||
"openATM": "Přístup k bankomatu",
|
||||
"account_deletion_failed": "Smazání účtu selhalo",
|
||||
"withdrawal_failed": "Výběr selhal",
|
||||
"deposit_failed": "Vklad selhal",
|
||||
"user_added_successfully": "úspěšně přidán",
|
||||
"user_addition_failed": "Přidání uživatele selhalo",
|
||||
"new_account_creation_failed": "Vytvoření nového účtu selhalo",
|
||||
"account_renamed_successfully": "Účet úspěšně přejmenován",
|
||||
"account_rename_failed": "Přejmenování účtu selhalo",
|
||||
"rename_account": "Změnit název",
|
||||
"no_framework_found": "Nebyl nalezen žádný framework",
|
||||
"cannot_send_self_money": "Nemůžeš poslat peníze sám sobě",
|
||||
"money_sent": "Poslal jsi %s %s",
|
||||
"received_money": "Obdržel jsi %s od %s",
|
||||
"no_money": "Nemáš dostatek peněz",
|
||||
"user_not_in_city": "Uživatel není ve městě",
|
||||
"transaction_description": "Transakce",
|
||||
"cannot_add_self": "Nemůžeš přidat sám sebe",
|
||||
"player_not_found": "Hráč nenalezen",
|
||||
"target_player_not_found": "Cílový hráč nenalezen",
|
||||
"user_already_in_account": "Uživatel je již na účtu",
|
||||
"account_not_found": "Účet nenalezen"
|
||||
}
|
112
resources/[tools]/ps-banking/locales/da.json
Normal file
112
resources/[tools]/ps-banking/locales/da.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"atm": "Hæveautomat",
|
||||
"cash": "Kontanter",
|
||||
"bank_balance": "Kontooversigt",
|
||||
"deposit_amount": "Indbetalingsbeløb",
|
||||
"withdraw_amount": "Hævningsbeløb",
|
||||
"submit": "Tilføj",
|
||||
"close": "Luk",
|
||||
"overview": "Oversigt",
|
||||
"bills": "Regninger",
|
||||
"history": "Historik",
|
||||
"withdraw": "Hæv",
|
||||
"deposit": "Indsæt",
|
||||
"stats": "Statistik",
|
||||
"transactions": "Transaktioner",
|
||||
"transaction": "Transaktion",
|
||||
"total": "Total",
|
||||
"search_transactions": "Søg i transaktioner...",
|
||||
"description": "Beskrivelse",
|
||||
"type": "Type",
|
||||
"time_ago": "Tid siden",
|
||||
"amount": "Beløb",
|
||||
"date": "Dato",
|
||||
"pay_invoice": "Betal faktura",
|
||||
"payment_completed": "Betaling fuldført",
|
||||
"from": "Fra",
|
||||
"delete_all_transactions": "Slet alle transaktioner",
|
||||
"are_you_sure": "Er du sikker?",
|
||||
"delete_confirmation": "Er du sikker på, at du vil slette alle dine transaktioner? (Gør kun dette, hvis menuen er langsom!)",
|
||||
"cancel": "Annullér",
|
||||
"confirm": "Bekræft",
|
||||
"history_empty": "Din historik er tom",
|
||||
"all_history_deleted": "Du har slettet din historik",
|
||||
"error": "Fejl",
|
||||
"success": "Succés",
|
||||
"new_cash": "Friske Kontanter",
|
||||
"withdraw_success": "Hævning gennemført",
|
||||
"withdraw_error": "Din bankbeholdning er for lav",
|
||||
"withdraw_button": "HÆV",
|
||||
"new_bank": "Ny Bank konto",
|
||||
"current_cash": "Nuværende Kontanter",
|
||||
"deposit_success": "Indbetaling Lykkedes",
|
||||
"deposit_error": "Du mangler kontanter",
|
||||
"deposit_button": "INDSÆT",
|
||||
"total_balance": "Total balance",
|
||||
"quick_actions": "Hurtige handlinger",
|
||||
"transfer_money": "Overfør Penge",
|
||||
"easy_transfer": "Nem-overførsel til personer",
|
||||
"transfer": "Overfør",
|
||||
"pay_bills": "Betal Regninger",
|
||||
"pay_pending_bills": "Betal hurtigt dine udestående regninger",
|
||||
"pay": "Betal",
|
||||
"withdraw_all_money": "Tøm kontoen",
|
||||
"withdraw_all_from_account": "Hæv alle dine penge fra din konto",
|
||||
"deposit_cash": "Indsæt Kontanter",
|
||||
"deposit_all_cash": "Indsæt alle dine kontanter på din konto",
|
||||
"weekly_summary": "Uge Oversigt",
|
||||
"income": "Indkomst",
|
||||
"expenses": "Udgifter",
|
||||
"report": "Rapport",
|
||||
"latest_transactions": "Seneste Transaktioner",
|
||||
"see_all": "SE ALLE",
|
||||
"unpaid_bills": "Ubetalte Fakturaer",
|
||||
"no_unpaid_bills": "Ingen ubetalte fakturaer",
|
||||
"confirm_pay_all_bills": "Er du sikker på, at du vil betale alle dine regninger?",
|
||||
"pay_all_bills": "Betal Alle Regninger",
|
||||
"pay_all_bills_success": "Du har betalt alle dine regninger!",
|
||||
"pay_all_bills_error": "Du har ingen regninger",
|
||||
"payment_method": "Betalingsmetode",
|
||||
"phone_number": "Telefonnummer",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID eller Telefonnummer",
|
||||
"no_cash_on_you": "Du har ingen kontanter på dig",
|
||||
"deposit_all_success": "Alle dine kontanter er indsat",
|
||||
"no_money_on_account": "Din konto er tom",
|
||||
"withdraw_all_success": "Du har hævet alle dine penge fra kontoen",
|
||||
"invoices": "Fakturaer",
|
||||
"statistics_reports": "Statistik og Rapportering",
|
||||
"balance_trend": "Balance oversigt",
|
||||
"balance": "Balance",
|
||||
"used": "Brugt",
|
||||
"month": "Måned",
|
||||
"balance_dkk": "Balance DKK",
|
||||
"withdrawn": "Du har hævet",
|
||||
"deposited": "Du har indsat",
|
||||
"no_transactions": "Ingen nylige transaktioner",
|
||||
"transactions_trend": "Transaktions Udvikling",
|
||||
"total_transactions": "Total Transaktioner",
|
||||
"accounts": "Konti",
|
||||
"account_number_copied": "Kontonummer kopieret til udklipsholder",
|
||||
"new_user_to_account": "Ny bruger til konto",
|
||||
"server_id": "Server ID",
|
||||
"add_user": "Tilføj Bruger",
|
||||
"new_account_name": "Nyt Kontonavn",
|
||||
"new_name": "Nyt Navn",
|
||||
"rename": "Omdøb",
|
||||
"create_new_account": "Opret Ny Konto",
|
||||
"account_holder": "Kontoholder",
|
||||
"initial_balance": "Startbeholdning",
|
||||
"create": "Opret",
|
||||
"delete_account": "Slet Konto",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Er du sikker på, at du vil slette denne konto?",
|
||||
"delete": "Slet",
|
||||
"remove_user_from_account": "Fjern Bruger fra Konto",
|
||||
"select_user": "Vælg Bruger",
|
||||
"remove": "Fjern",
|
||||
"withdraw_from_account": "Hæv fra Konto",
|
||||
"deposit_to_account": "Indsæt på Konto",
|
||||
"removed_successfully": "Fjernet Succesfuldt",
|
||||
"select_account_and_user": "Vælg venligst en konto og en bruger",
|
||||
"account_deleted_successfully": "Konto sletning, gennemført!"
|
||||
}
|
139
resources/[tools]/ps-banking/locales/de.json
Normal file
139
resources/[tools]/ps-banking/locales/de.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "Geldautomat",
|
||||
"cash": "Bargeld",
|
||||
"bank_balance": "Kontostand",
|
||||
"deposit_amount": "Einzahlungsbetrag",
|
||||
"withdraw_amount": "Abhebungsbetrag",
|
||||
"submit": "Bestätigen",
|
||||
"close": "Schließen",
|
||||
"overview": "Überblick",
|
||||
"bills": "Rechnungen",
|
||||
"history": "Verlauf",
|
||||
"withdraw": "Abheben",
|
||||
"deposit": "Einzahlen",
|
||||
"stats": "Statistiken",
|
||||
"transactions": "Transaktionen",
|
||||
"transaction": "Transaktion",
|
||||
"total": "Gesamt",
|
||||
"search_transactions": "Transaktionen suchen...",
|
||||
"description": "Beschreibung",
|
||||
"type": "Typ",
|
||||
"time_ago": "Vor",
|
||||
"amount": "Betrag",
|
||||
"date": "Datum",
|
||||
"pay_invoice": "Rechnung bezahlen",
|
||||
"payment_completed": "Zahlung abgeschlossen",
|
||||
"from": "Von",
|
||||
"delete_all_transactions": "Alle Transaktionen löschen",
|
||||
"are_you_sure": "Bist du sicher?",
|
||||
"delete_confirmation": "Möchtest du wirklich alle deine Transaktionen löschen? (Nur tun, wenn das Menü hängt!)",
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"history_empty": "Dein Verlauf ist leer",
|
||||
"all_history_deleted": "Du hast deinen gesamten Verlauf gelöscht",
|
||||
"error": "Fehler",
|
||||
"success": "Erfolg",
|
||||
"new_cash": "Neues Bargeld",
|
||||
"withdraw_success": "Abhebung erfolgreich",
|
||||
"withdraw_error": "Dein Bankkonto hat nicht genügend Guthaben",
|
||||
"withdraw_button": "ABHEBEN",
|
||||
"new_bank": "Neuer Kontostand",
|
||||
"current_cash": "Aktuelles Bargeld",
|
||||
"deposit_success": "Einzahlung erfolgreich",
|
||||
"deposit_error": "Du hast nicht genügend Bargeld",
|
||||
"deposit_button": "EINZAHLEN",
|
||||
"total_balance": "Gesamtguthaben",
|
||||
"quick_actions": "Schnellaktionen",
|
||||
"transfer_money": "Geld überweisen",
|
||||
"easy_transfer": "Einfach Geld an Personen überweisen",
|
||||
"transfer": "Überweisen",
|
||||
"pay_bills": "Rechnungen bezahlen",
|
||||
"pay_pending_bills": "Schnell deine ausstehenden Rechnungen bezahlen",
|
||||
"pay": "Bezahlen",
|
||||
"withdraw_all_money": "Alles Geld abheben",
|
||||
"withdraw_all_from_account": "Hebe dein gesamtes Geld von deinem Konto ab",
|
||||
"deposit_cash": "Bargeld einzahlen",
|
||||
"deposit_all_cash": "Zahle dein gesamtes Bargeld auf dein Konto ein",
|
||||
"weekly_summary": "Wöchentliche Zusammenfassung",
|
||||
"income": "Einkommen",
|
||||
"expenses": "Ausgaben",
|
||||
"report": "Bericht",
|
||||
"latest_transactions": "Neueste Transaktionen",
|
||||
"see_all": "ALLE ANSEHEN",
|
||||
"unpaid_bills": "Unbezahlte Rechnungen",
|
||||
"no_unpaid_bills": "Keine unbezahlten Rechnungen",
|
||||
"confirm_pay_all_bills": "Möchtest du wirklich alle deine Rechnungen bezahlen?",
|
||||
"pay_all_bills": "Alle Rechnungen bezahlen",
|
||||
"pay_all_bills_success": "Du hast alle deine Rechnungen bezahlt!",
|
||||
"pay_all_bills_error": "Du hast keine Rechnungen",
|
||||
"payment_method": "Zahlungsmethode",
|
||||
"phone_number": "Telefonnummer",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID oder Telefonnummer",
|
||||
"no_cash_on_you": "Du hast kein Bargeld bei dir",
|
||||
"deposit_all_success": "Dein gesamtes Bargeld wurde eingezahlt",
|
||||
"no_money_on_account": "Dein Konto ist leer",
|
||||
"withdraw_all_success": "Du hast dein gesamtes Geld vom Konto abgehoben",
|
||||
"invoices": "Rechnungen",
|
||||
"statistics_reports": "Statistiken und Berichte",
|
||||
"balance_trend": "Kontostand-Trend",
|
||||
"balance": "Kontostand",
|
||||
"used": "Verwendet",
|
||||
"month": "Monat",
|
||||
"balance_dkk": "Kontostand",
|
||||
"withdrawn": "Du hast abgehoben",
|
||||
"deposited": "Du hast eingezahlt",
|
||||
"no_transactions": "Keine aktuellen Transaktionen",
|
||||
"transactions_trend": "Transaktions-Trend",
|
||||
"total_transactions": "Gesamttransaktionen",
|
||||
"accounts": "Konten",
|
||||
"account_number_copied": "Kontonummer in die Zwischenablage kopiert",
|
||||
"new_user_to_account": "Neuer Benutzer zum Konto hinzufügen",
|
||||
"server_id": "Server-ID",
|
||||
"add_user": "Benutzer hinzufügen",
|
||||
"new_account_name": "Neuer Kontoname",
|
||||
"new_name": "Neuer Name",
|
||||
"rename": "Umbenennen",
|
||||
"create_new_account": "Neues Konto erstellen",
|
||||
"account_holder": "Kontoinhaber",
|
||||
"initial_balance": "Anfangsguthaben",
|
||||
"create": "Erstellen",
|
||||
"delete_account": "Konto löschen",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Möchtest du dieses Konto wirklich löschen?",
|
||||
"delete": "Löschen",
|
||||
"remove_user_from_account": "Benutzer vom Konto entfernen",
|
||||
"select_user": "Benutzer auswählen",
|
||||
"remove": "Entfernen",
|
||||
"withdraw_from_account": "Vom Konto abheben",
|
||||
"deposit_to_account": "Auf Konto einzahlen",
|
||||
"removed_successfully": "Erfolgreich entfernt",
|
||||
"select_account_and_user": "Bitte wähle ein Konto und einen Benutzer aus",
|
||||
"account_deleted_successfully": "Konto erfolgreich gelöscht",
|
||||
"new_account_created_successfully": "Neues Konto erfolgreich erstellt",
|
||||
"withdrew": "Abgehoben",
|
||||
"successfully": "Erfolgreich",
|
||||
"select_valid_account_and_amount": "Bitte wähle ein gültiges Konto und einen Betrag aus",
|
||||
"openBank": "Bankzugang",
|
||||
"openATM": "Geldautomatenzugang",
|
||||
"account_deletion_failed": "Kontolöschung fehlgeschlagen",
|
||||
"withdrawal_failed": "Abhebung fehlgeschlagen",
|
||||
"deposit_failed": "Einzahlung fehlgeschlagen",
|
||||
"user_added_successfully": "Erfolgreich hinzugefügt",
|
||||
"user_addition_failed": "Benutzer konnte nicht hinzugefügt werden",
|
||||
"new_account_creation_failed": "Erstellung eines neuen Kontos fehlgeschlagen",
|
||||
"account_renamed_successfully": "Konto erfolgreich umbenannt",
|
||||
"account_rename_failed": "Umbenennung des Kontos fehlgeschlagen",
|
||||
"rename_account": "Namen ändern",
|
||||
"no_framework_found": "Kein Framework gefunden",
|
||||
"cannot_send_self_money": "Du kannst dir selbst kein Geld senden",
|
||||
"money_sent": "Du hast %s an %s gesendet",
|
||||
"received_money": "Du hast %s von %s erhalten",
|
||||
"no_money": "Du hast nicht genug Geld",
|
||||
"user_not_in_city": "Benutzer ist nicht in der Stadt",
|
||||
"transaction_description": "Transaktion",
|
||||
"cannot_add_self": "Du kannst dich nicht selbst hinzufügen",
|
||||
"player_not_found": "Spieler nicht gefunden",
|
||||
"target_player_not_found": "Zielspieler nicht gefunden",
|
||||
"user_already_in_account": "Benutzer ist bereits im Konto",
|
||||
"account_not_found": "Konto nicht gefunden"
|
||||
}
|
139
resources/[tools]/ps-banking/locales/en.json
Normal file
139
resources/[tools]/ps-banking/locales/en.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "ATM",
|
||||
"cash": "Cash",
|
||||
"bank_balance": "Bank Balance",
|
||||
"deposit_amount": "Deposit Amount",
|
||||
"withdraw_amount": "Withdraw Amount",
|
||||
"submit": "Submit",
|
||||
"close": "Close",
|
||||
"overview": "Overview",
|
||||
"bills": "Bills",
|
||||
"history": "History",
|
||||
"withdraw": "Withdraw",
|
||||
"deposit": "Deposit",
|
||||
"stats": "Stats",
|
||||
"transactions": "Transactions",
|
||||
"transaction": "Transaction",
|
||||
"total": "Total",
|
||||
"search_transactions": "Search transactions...",
|
||||
"description": "Description",
|
||||
"type": "Type",
|
||||
"time_ago": "Time Ago",
|
||||
"amount": "Amount",
|
||||
"date": "Date",
|
||||
"pay_invoice": "Pay Invoice",
|
||||
"payment_completed": "Payment Completed",
|
||||
"from": "From",
|
||||
"delete_all_transactions": "Delete All Transactions",
|
||||
"are_you_sure": "Are you sure?",
|
||||
"delete_confirmation": "Are you sure you want to delete all your transactions? (Only do this if the menu lags!)",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"history_empty": "Your history is empty",
|
||||
"all_history_deleted": "You have deleted all your history",
|
||||
"error": "Error",
|
||||
"success": "Success",
|
||||
"new_cash": "New Cash",
|
||||
"withdraw_success": "Withdrawal Successful",
|
||||
"withdraw_error": "Your bank account does not have enough funds",
|
||||
"withdraw_button": "WITHDRAW",
|
||||
"new_bank": "New Bank Balance",
|
||||
"current_cash": "Current Cash",
|
||||
"deposit_success": "Deposit Successful",
|
||||
"deposit_error": "You do not have enough cash",
|
||||
"deposit_button": "DEPOSIT",
|
||||
"total_balance": "Total Balance",
|
||||
"quick_actions": "Quick Actions",
|
||||
"transfer_money": "Transfer Money",
|
||||
"easy_transfer": "Easily transfer money to people",
|
||||
"transfer": "Transfer",
|
||||
"pay_bills": "Pay Bills",
|
||||
"pay_pending_bills": "Quickly pay your pending bills",
|
||||
"pay": "Pay",
|
||||
"withdraw_all_money": "Withdraw All Money",
|
||||
"withdraw_all_from_account": "Withdraw all your money from your account",
|
||||
"deposit_cash": "Deposit Cash",
|
||||
"deposit_all_cash": "Deposit all your cash into your account",
|
||||
"weekly_summary": "Weekly Summary",
|
||||
"income": "Income",
|
||||
"expenses": "Expenses",
|
||||
"report": "Report",
|
||||
"latest_transactions": "Latest Transactions",
|
||||
"see_all": "SEE ALL",
|
||||
"unpaid_bills": "Unpaid Invoices",
|
||||
"no_unpaid_bills": "No unpaid invoices",
|
||||
"confirm_pay_all_bills": "Are you sure you want to pay all your bills?",
|
||||
"pay_all_bills": "Pay All Bills",
|
||||
"pay_all_bills_success": "You have paid all your bills!",
|
||||
"pay_all_bills_error": "You have no bills",
|
||||
"payment_method": "Payment Method",
|
||||
"phone_number": "Phone Number",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID or Phone Number",
|
||||
"no_cash_on_you": "You have no cash on you",
|
||||
"deposit_all_success": "All your cash has been deposited",
|
||||
"no_money_on_account": "Your account is empty",
|
||||
"withdraw_all_success": "You have withdrawn all your money from the account",
|
||||
"invoices": "Invoices",
|
||||
"statistics_reports": "Statistics and Reports",
|
||||
"balance_trend": "Balance Trend",
|
||||
"balance": "Balance",
|
||||
"used": "Used",
|
||||
"month": "Month",
|
||||
"balance_dkk": "Balance",
|
||||
"withdrawn": "You have withdrawn",
|
||||
"deposited": "You have deposited",
|
||||
"no_transactions": "No recent transactions",
|
||||
"transactions_trend": "Transactions Trend",
|
||||
"total_transactions": "Total Transactions",
|
||||
"accounts": "Accounts",
|
||||
"account_number_copied": "Account number copied to clipboard",
|
||||
"new_user_to_account": "New user to account",
|
||||
"server_id": "Server ID",
|
||||
"add_user": "Add User",
|
||||
"new_account_name": "New Account Name",
|
||||
"new_name": "New Name",
|
||||
"rename": "Rename",
|
||||
"create_new_account": "Create New Account",
|
||||
"account_holder": "Account Holder",
|
||||
"initial_balance": "Initial Balance",
|
||||
"create": "Create",
|
||||
"delete_account": "Delete Account",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Are you sure you want to delete this account?",
|
||||
"delete": "Delete",
|
||||
"remove_user_from_account": "Remove User from Account",
|
||||
"select_user": "Select User",
|
||||
"remove": "Remove",
|
||||
"withdraw_from_account": "Withdraw from Account",
|
||||
"deposit_to_account": "Deposit to Account",
|
||||
"removed_successfully": "Removed Successfully",
|
||||
"select_account_and_user": "Please select an account and a user",
|
||||
"account_deleted_successfully": "Account deleted successfully",
|
||||
"new_account_created_successfully": "New account created successfully",
|
||||
"withdrew": "Withdrew",
|
||||
"successfully": "Successfully",
|
||||
"select_valid_account_and_amount": "Please select a valid account and amount",
|
||||
"openBank": "Access Bank",
|
||||
"openATM": "Access ATM",
|
||||
"account_deletion_failed": "Account deletion failed",
|
||||
"withdrawal_failed": "Withdrawal failed",
|
||||
"deposit_failed": "Deposit failed",
|
||||
"user_added_successfully": "User added successfully",
|
||||
"user_addition_failed": "Failed to add user",
|
||||
"new_account_creation_failed": "Failed to create new account",
|
||||
"account_renamed_successfully": "Account renamed successfully",
|
||||
"account_rename_failed": "Account rename failed",
|
||||
"rename_account": "Change name",
|
||||
"no_framework_found": "No framework found",
|
||||
"cannot_send_self_money": "You cannot send money to yourself",
|
||||
"money_sent": "You have sent %s to %s",
|
||||
"received_money": "You have received %s from %s",
|
||||
"no_money": "You do not have enough money",
|
||||
"user_not_in_city": "User is not in the city",
|
||||
"transaction_description": "Transaction",
|
||||
"cannot_add_self": "You cannot add yourself",
|
||||
"player_not_found": "Player not found",
|
||||
"target_player_not_found": "Target player not found",
|
||||
"user_already_in_account": "User is already in the account",
|
||||
"account_not_found": "Account not found"
|
||||
}
|
140
resources/[tools]/ps-banking/locales/es.json
Normal file
140
resources/[tools]/ps-banking/locales/es.json
Normal file
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"atm": "Cajero Automático",
|
||||
"cash": "Efectivo",
|
||||
"bank_balance": "Saldo Bancario",
|
||||
"deposit_amount": "Monto a Depositar",
|
||||
"withdraw_amount": "Monto a Retirar",
|
||||
"submit": "Enviar",
|
||||
"close": "Cerrar",
|
||||
"overview": "Resumen",
|
||||
"bills": "Facturas",
|
||||
"history": "Historial",
|
||||
"withdraw": "Retirar",
|
||||
"deposit": "Depositar",
|
||||
"stats": "Estadísticas",
|
||||
"transactions": "Transacciones",
|
||||
"transaction": "Transacción",
|
||||
"total": "Total",
|
||||
"search_transactions": "Buscar transacciones...",
|
||||
"description": "Descripción",
|
||||
"type": "Tipo",
|
||||
"time_ago": "Hace Tiempo",
|
||||
"amount": "Cantidad",
|
||||
"date": "Fecha",
|
||||
"pay_invoice": "Pagar Factura",
|
||||
"payment_completed": "Pago Completado",
|
||||
"from": "De",
|
||||
"delete_all_transactions": "Eliminar Todas las Transacciones",
|
||||
"are_you_sure": "¿Estás seguro?",
|
||||
"delete_confirmation": "¿Estás seguro de que deseas eliminar todas tus transacciones? (¡Haz esto solo si el menú se retrasa!)",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"history_empty": "Tu historial está vacío",
|
||||
"all_history_deleted": "Has eliminado todo tu historial",
|
||||
"error": "Error",
|
||||
"success": "Éxito",
|
||||
"new_cash": "Nuevo Efectivo",
|
||||
"withdraw_success": "Retiro Exitoso",
|
||||
"withdraw_error": "Tu cuenta bancaria no tiene suficientes fondos",
|
||||
"withdraw_button": "RETIRAR",
|
||||
"new_bank": "Nuevo Saldo Bancario",
|
||||
"current_cash": "Efectivo Actual",
|
||||
"deposit_success": "Depósito Exitoso",
|
||||
"deposit_error": "No tienes suficiente efectivo",
|
||||
"deposit_button": "DEPOSITAR",
|
||||
"total_balance": "Saldo Total",
|
||||
"quick_actions": "Acciones Rápidas",
|
||||
"transfer_money": "Transferir Dinero",
|
||||
"easy_transfer": "Transfiere dinero fácilmente a personas",
|
||||
"transfer": "Transferir",
|
||||
"pay_bills": "Pagar Facturas",
|
||||
"pay_pending_bills": "Paga rápidamente tus facturas pendientes",
|
||||
"pay": "Pagar",
|
||||
"withdraw_all_money": "Retirar Todo el Dinero",
|
||||
"withdraw_all_from_account": "Retirar todo tu dinero de tu cuenta",
|
||||
"deposit_cash": "Depositar Efectivo",
|
||||
"deposit_all_cash": "Depositar todo tu efectivo en tu cuenta",
|
||||
"weekly_summary": "Resumen Semanal",
|
||||
"income": "Ingresos",
|
||||
"expenses": "Gastos",
|
||||
"report": "Informe",
|
||||
"latest_transactions": "Últimas Transacciones",
|
||||
"see_all": "VER TODO",
|
||||
"unpaid_bills": "Facturas No Pagadas",
|
||||
"no_unpaid_bills": "No hay facturas no pagadas",
|
||||
"confirm_pay_all_bills": "¿Estás seguro de que deseas pagar todas tus facturas?",
|
||||
"pay_all_bills": "Pagar Todas las Facturas",
|
||||
"pay_all_bills_success": "¡Has pagado todas tus facturas!",
|
||||
"pay_all_bills_error": "No tienes facturas",
|
||||
"payment_method": "Método de Pago",
|
||||
"phone_number": "Número de Teléfono",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID o Número de Teléfono",
|
||||
"no_cash_on_you": "No tienes efectivo contigo",
|
||||
"deposit_all_success": "Todo tu efectivo ha sido depositado",
|
||||
"no_money_on_account": "Tu cuenta está vacía",
|
||||
"withdraw_all_success": "Has retirado todo tu dinero de la cuenta",
|
||||
"invoices": "Facturas",
|
||||
"statistics_reports": "Estadísticas e Informes",
|
||||
"balance_trend": "Tendencia de Saldo",
|
||||
"balance": "Saldo",
|
||||
"used": "Usado",
|
||||
"month": "Mes",
|
||||
"balance_dkk": "Saldo",
|
||||
"withdrawn": "Has retirado",
|
||||
"deposited": "Has depositado",
|
||||
"no_transactions": "No hay transacciones recientes",
|
||||
"transactions_trend": "Tendencia de Transacciones",
|
||||
"total_transactions": "Total de Transacciones",
|
||||
"accounts": "Cuentas",
|
||||
"account_number_copied": "Número de cuenta copiado al portapapeles",
|
||||
"new_user_to_account": "Nuevo usuario en la cuenta",
|
||||
"server_id": "ID del Servidor",
|
||||
"add_user": "Añadir Usuario",
|
||||
"new_account_name": "Nuevo Nombre de Cuenta",
|
||||
"new_name": "Nuevo Nombre",
|
||||
"rename": "Renombrar",
|
||||
"create_new_account": "Crear Nueva Cuenta",
|
||||
"account_holder": "Titular de la Cuenta",
|
||||
"initial_balance": "Saldo Inicial",
|
||||
"create": "Crear",
|
||||
"delete_account": "Eliminar Cuenta",
|
||||
"are_you_sure_you_want_to_delete_this_account": "¿Estás seguro de que deseas eliminar esta cuenta?",
|
||||
"delete": "Eliminar",
|
||||
"remove_user_from_account": "Eliminar Usuario de la Cuenta",
|
||||
"select_user": "Seleccionar Usuario",
|
||||
"remove": "Eliminar",
|
||||
"withdraw_from_account": "Retirar de la Cuenta",
|
||||
"deposit_to_account": "Depositar en la Cuenta",
|
||||
"removed_successfully": "Eliminado Exitosamente",
|
||||
"select_account_and_user": "Por favor, selecciona una cuenta y un usuario",
|
||||
"account_deleted_successfully": "Cuenta eliminada exitosamente",
|
||||
"new_account_created_successfully": "Nueva cuenta creada exitosamente",
|
||||
"withdrew": "Retiró",
|
||||
"successfully": "Exitosamente",
|
||||
"select_valid_account_and_amount": "Por favor, selecciona una cuenta válida y una cantidad",
|
||||
"openBank": "Acceder al Banco",
|
||||
"openATM": "Acceder al Cajero Automático",
|
||||
"account_deletion_failed": "Fallo al eliminar la cuenta",
|
||||
"withdrawal_failed": "Fallo en el retiro",
|
||||
"deposit_failed": "Fallo en el depósito",
|
||||
"user_added_successfully": "Usuario añadido exitosamente",
|
||||
"user_addition_failed": "Fallo al añadir usuario",
|
||||
"new_account_creation_failed": "Fallo al crear nueva cuenta",
|
||||
"account_renamed_successfully": "Cuenta renombrada exitosamente",
|
||||
"account_rename_failed": "Fallo al renombrar la cuenta",
|
||||
"rename_account": "Cambiar nombre",
|
||||
"no_framework_found": "No se encontró el framework",
|
||||
"cannot_send_self_money": "No puedes enviarte dinero a ti mismo",
|
||||
"money_sent": "Has enviado %s a %s",
|
||||
"received_money": "Has recibido %s de %s",
|
||||
"no_money": "No tienes suficiente dinero",
|
||||
"user_not_in_city": "El usuario no está en la ciudad",
|
||||
"transaction_description": "Transacción",
|
||||
"cannot_add_self": "No puedes añadirte a ti mismo",
|
||||
"player_not_found": "Jugador no encontrado",
|
||||
"target_player_not_found": "Jugador objetivo no encontrado",
|
||||
"user_already_in_account": "El usuario ya está en la cuenta",
|
||||
"account_not_found": "Cuenta no encontrada"
|
||||
}
|
||||
|
139
resources/[tools]/ps-banking/locales/fr.json
Normal file
139
resources/[tools]/ps-banking/locales/fr.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "ATM",
|
||||
"cash": "Argent liquide",
|
||||
"bank_balance": "Solde bancaire",
|
||||
"deposit_amount": "Montant du dépôt",
|
||||
"withdraw_amount": "Montant du retrait",
|
||||
"submit": "Soumettre",
|
||||
"close": "Fermer",
|
||||
"overview": "Aperçu",
|
||||
"bills": "Factures",
|
||||
"history": "Historique",
|
||||
"withdraw": "Retirer",
|
||||
"deposit": "Déposer",
|
||||
"stats": "Statistiques",
|
||||
"transactions": "Transactions",
|
||||
"transaction": "Transaction",
|
||||
"total": "Total",
|
||||
"search_transactions": "Rechercher des transactions...",
|
||||
"description": "Description",
|
||||
"type": "Type",
|
||||
"time_ago": "Il y a",
|
||||
"amount": "Montant",
|
||||
"date": "Date",
|
||||
"pay_invoice": "Payer la facture",
|
||||
"payment_completed": "Paiement effectué",
|
||||
"from": "De",
|
||||
"delete_all_transactions": "Supprimer toutes les transactions",
|
||||
"are_you_sure": "Êtes-vous sûr?",
|
||||
"delete_confirmation": "Êtes-vous sûr de vouloir supprimer toutes vos transactions ? (Faites cela uniquement si le menu est lent !)",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer",
|
||||
"history_empty": "Votre historique est vide",
|
||||
"all_history_deleted": "Vous avez supprimé tout votre historique",
|
||||
"error": "Erreur",
|
||||
"success": "Succès",
|
||||
"new_cash": "Nouvel argent liquide",
|
||||
"withdraw_success": "Retrait réussi",
|
||||
"withdraw_error": "Votre compte bancaire n'a pas assez de fonds",
|
||||
"withdraw_button": "RETIRER",
|
||||
"new_bank": "Nouveau solde bancaire",
|
||||
"current_cash": "Argent liquide actuel",
|
||||
"deposit_success": "Dépôt réussi",
|
||||
"deposit_error": "Vous n'avez pas assez d'argent liquide",
|
||||
"deposit_button": "DÉPOSER",
|
||||
"total_balance": "Solde total",
|
||||
"quick_actions": "Actions rapides",
|
||||
"transfer_money": "Transférer de l'argent",
|
||||
"easy_transfer": "Transférer facilement de l'argent aux personnes",
|
||||
"transfer": "Transférer",
|
||||
"pay_bills": "Payer les factures",
|
||||
"pay_pending_bills": "Payer rapidement vos factures en attente",
|
||||
"pay": "Payer",
|
||||
"withdraw_all_money": "Retirer tout l'argent",
|
||||
"withdraw_all_from_account": "Retirer tout votre argent de votre compte",
|
||||
"deposit_cash": "Déposer de l'argent liquide",
|
||||
"deposit_all_cash": "Déposer tout votre argent liquide sur votre compte",
|
||||
"weekly_summary": "Résumé hebdomadaire",
|
||||
"income": "Revenus",
|
||||
"expenses": "Dépenses",
|
||||
"report": "Rapport",
|
||||
"latest_transactions": "Dernières transactions",
|
||||
"see_all": "VOIR TOUT",
|
||||
"unpaid_bills": "Factures impayées",
|
||||
"no_unpaid_bills": "Aucune facture impayée",
|
||||
"confirm_pay_all_bills": "Êtes-vous sûr de vouloir payer toutes vos factures ?",
|
||||
"pay_all_bills": "Payer toutes les factures",
|
||||
"pay_all_bills_success": "Vous avez payé toutes vos factures !",
|
||||
"pay_all_bills_error": "Vous n'avez aucune facture",
|
||||
"payment_method": "Méthode de paiement",
|
||||
"phone_number": "Numéro de téléphone",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID ou numéro de téléphone",
|
||||
"no_cash_on_you": "Vous n'avez pas d'argent liquide sur vous",
|
||||
"deposit_all_success": "Tout votre argent liquide a été déposé",
|
||||
"no_money_on_account": "Votre compte est vide",
|
||||
"withdraw_all_success": "Vous avez retiré tout votre argent du compte",
|
||||
"invoices": "Factures",
|
||||
"statistics_reports": "Statistiques et rapports",
|
||||
"balance_trend": "Tendance du solde",
|
||||
"balance": "Solde",
|
||||
"used": "Utilisé",
|
||||
"month": "Mois",
|
||||
"balance_dkk": "Solde",
|
||||
"withdrawn": "Vous avez retiré",
|
||||
"deposited": "Vous avez déposé",
|
||||
"no_transactions": "Aucune transaction récente",
|
||||
"transactions_trend": "Tendance des transactions",
|
||||
"total_transactions": "Total des transactions",
|
||||
"accounts": "Comptes",
|
||||
"account_number_copied": "Numéro de compte copié dans le presse-papiers",
|
||||
"new_user_to_account": "Nouvel utilisateur sur le compte",
|
||||
"server_id": "ID serveur",
|
||||
"add_user": "Ajouter un utilisateur",
|
||||
"new_account_name": "Nouveau nom de compte",
|
||||
"new_name": "Nouveau nom",
|
||||
"rename": "Renommer",
|
||||
"create_new_account": "Créer un nouveau compte",
|
||||
"account_holder": "Titulaire du compte",
|
||||
"initial_balance": "Solde initial",
|
||||
"create": "Créer",
|
||||
"delete_account": "Supprimer le compte",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Êtes-vous sûr de vouloir supprimer ce compte ?",
|
||||
"delete": "Supprimer",
|
||||
"remove_user_from_account": "Supprimer l'utilisateur du compte",
|
||||
"select_user": "Sélectionner l'utilisateur",
|
||||
"remove": "Supprimer",
|
||||
"withdraw_from_account": "Retirer du compte",
|
||||
"deposit_to_account": "Déposer sur le compte",
|
||||
"removed_successfully": "Supprimé avec succès",
|
||||
"select_account_and_user": "Veuillez sélectionner un compte et un utilisateur",
|
||||
"account_deleted_successfully": "Compte supprimé avec succès",
|
||||
"new_account_created_successfully": "Nouveau compte créé avec succès",
|
||||
"withdrew": "Retiré",
|
||||
"successfully": "Avec succès",
|
||||
"select_valid_account_and_amount": "Veuillez sélectionner un compte valide et un montant",
|
||||
"openBank": "Accéder à la banque",
|
||||
"openATM": "Accéder au ATM",
|
||||
"account_deletion_failed": "Échec de la suppression du compte",
|
||||
"withdrawal_failed": "Échec du retrait",
|
||||
"deposit_failed": "Échec du dépôt",
|
||||
"user_added_successfully": "Ajouté avec succès",
|
||||
"user_addition_failed": "Échec de l'ajout de l'utilisateur",
|
||||
"new_account_creation_failed": "Échec de la création du nouveau compte",
|
||||
"account_renamed_successfully": "Compte renommé avec succès",
|
||||
"account_rename_failed": "Échec du renommage du compte",
|
||||
"rename_account": "Changer le nom",
|
||||
"no_framework_found": "Aucun framework trouvé",
|
||||
"cannot_send_self_money": "Vous ne pouvez pas vous envoyer de l'argent",
|
||||
"money_sent": "Vous avez envoyé %s à %s",
|
||||
"received_money": "Vous avez reçu %s de %s",
|
||||
"no_money": "Vous n'avez pas assez d'argent",
|
||||
"user_not_in_city": "L'utilisateur n'est pas en ville",
|
||||
"transaction_description": "Transaction",
|
||||
"cannot_add_self": "Vous ne pouvez pas vous ajouter",
|
||||
"player_not_found": "Joueur non trouvé",
|
||||
"target_player_not_found": "Joueur cible non trouvé",
|
||||
"user_already_in_account": "L'utilisateur est déjà dans le compte",
|
||||
"account_not_found": "Compte non trouvé"
|
||||
}
|
140
resources/[tools]/ps-banking/locales/nl.json
Normal file
140
resources/[tools]/ps-banking/locales/nl.json
Normal file
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"atm": "Geldautomaat",
|
||||
"cash": "Contant",
|
||||
"bank_balance": "Banksaldo",
|
||||
"deposit_amount": "Stortingsbedrag",
|
||||
"withdraw_amount": "Opnamembedrag",
|
||||
"submit": "Verzenden",
|
||||
"close": "Sluiten",
|
||||
"overview": "Overzicht",
|
||||
"bills": "Rekeningen",
|
||||
"history": "Geschiedenis",
|
||||
"withdraw": "Opnemen",
|
||||
"deposit": "Storten",
|
||||
"stats": "Statistieken",
|
||||
"transactions": "Transacties",
|
||||
"transaction": "Transactie",
|
||||
"total": "Totaal",
|
||||
"search_transactions": "Zoek transacties...",
|
||||
"description": "Omschrijving",
|
||||
"type": "Type",
|
||||
"time_ago": "Tijd geleden",
|
||||
"amount": "Bedrag",
|
||||
"date": "Datum",
|
||||
"pay_invoice": "Factuur betalen",
|
||||
"payment_completed": "Betaling voltooid",
|
||||
"from": "Van",
|
||||
"delete_all_transactions": "Verwijder alle transacties",
|
||||
"are_you_sure": "Weet je het zeker?",
|
||||
"delete_confirmation": "Weet je zeker dat je al je transacties wilt verwijderen? (Doe dit alleen wanneer je lag ervaart!)",
|
||||
"cancel": "Annuleren",
|
||||
"confirm": "Bevestigen",
|
||||
"history_empty": "Je geschiedenis is leeg",
|
||||
"all_history_deleted": "Je hebt al je geschiedenis verwijderd",
|
||||
"error": "Fout",
|
||||
"success": "Succes",
|
||||
"new_cash": "Nieuw Contant",
|
||||
"withdraw_success": "Opname geslaagd",
|
||||
"withdraw_error": "Je bankrekening heeft niet genoeg saldo",
|
||||
"withdraw_button": "OPNEMEN",
|
||||
"new_bank": "Nieuw Banksaldo",
|
||||
"current_cash": "Huidig Contant",
|
||||
"deposit_success": "Storting geslaagd",
|
||||
"deposit_error": "Je hebt niet genoeg contant geld",
|
||||
"deposit_button": "STORTEN",
|
||||
"total_balance": "Totaal Saldo",
|
||||
"quick_actions": "Snelle Acties",
|
||||
"transfer_money": "Geld Overmaken",
|
||||
"easy_transfer": "Eenvoudig geld overmaken naar mensen",
|
||||
"transfer": "Overmaken",
|
||||
"pay_bills": "Rekeningen Betalen",
|
||||
"pay_pending_bills": "Snel je openstaande rekeningen betalen",
|
||||
"pay": "Betalen",
|
||||
"withdraw_all_money": "Trek al het geld op",
|
||||
"withdraw_all_from_account": "Trek al je geld van je rekening op",
|
||||
"deposit_cash": "Contant Geld Storten",
|
||||
"deposit_all_cash": "Stort al je contant geld op je rekening",
|
||||
"weekly_summary": "Wekelijks Overzicht",
|
||||
"income": "Inkomen",
|
||||
"expenses": "Uitgaven",
|
||||
"report": "Rapport",
|
||||
"latest_transactions": "Laatste Transacties",
|
||||
"see_all": "TOON ALLE",
|
||||
"unpaid_bills": "Onbetaalde Facturen",
|
||||
"no_unpaid_bills": "Geen onbetaalde facturen",
|
||||
"confirm_pay_all_bills": "Weet je zeker dat je al je rekeningen wilt betalen?",
|
||||
"pay_all_bills": "Betaal Alle Rekeningen",
|
||||
"pay_all_bills_success": "Je hebt al je rekeningen betaald!",
|
||||
"pay_all_bills_error": "Je hebt geen rekeningen",
|
||||
"payment_method": "Betaalmethode",
|
||||
"phone_number": "Telefoonnummer",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID of Telefoonnummer",
|
||||
"no_cash_on_you": "Je hebt geen contant geld bij je",
|
||||
"deposit_all_success": "Al je contant geld is gestort",
|
||||
"no_money_on_account": "Je rekening is leeg",
|
||||
"withdraw_all_success": "Je hebt al je geld van de rekening opgenomen",
|
||||
"invoices": "Facturen",
|
||||
"statistics_reports": "Statistieken en Rapporten",
|
||||
"balance_trend": "Saldo Trend",
|
||||
"balance": "Saldo",
|
||||
"used": "Gebruikt",
|
||||
"month": "Maand",
|
||||
"balance_dkk": "Saldo",
|
||||
"withdrawn": "Je hebt opgenomen",
|
||||
"deposited": "Je hebt gestort",
|
||||
"no_transactions": "Geen recente transacties",
|
||||
"transactions_trend": "Transacties Trend",
|
||||
"total_transactions": "Totaal Aantal Transacties",
|
||||
"accounts": "Rekeningen",
|
||||
"account_number_copied": "Rekeningnummer gekopieerd naar klembord",
|
||||
"new_user_to_account": "Nieuwe gebruiker aan rekening",
|
||||
"server_id": "Server ID",
|
||||
"add_user": "Voeg Gebruiker Toe",
|
||||
"new_account_name": "Nieuwe Rekeningnaam",
|
||||
"new_name": "Nieuwe Naam",
|
||||
"rename": "Hernoemen",
|
||||
"create_new_account": "Nieuwe Rekening Aanmaken",
|
||||
"account_holder": "Rekeninghouder",
|
||||
"initial_balance": "Aanvankelijk Saldo",
|
||||
"create": "Aanmaken",
|
||||
"delete_account": "Verwijder Rekening",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Weet je zeker dat je deze rekening wilt verwijderen?",
|
||||
"delete": "Verwijderen",
|
||||
"remove_user_from_account": "Verwijder Gebruiker van Rekening",
|
||||
"select_user": "Selecteer Gebruiker",
|
||||
"remove": "Verwijderen",
|
||||
"withdraw_from_account": "Opnemen van Rekening",
|
||||
"deposit_to_account": "Storten op Rekening",
|
||||
"removed_successfully": "Succesvol verwijderd",
|
||||
"select_account_and_user": "Selecteer een rekening en een gebruiker",
|
||||
"account_deleted_successfully": "Rekening succesvol verwijderd",
|
||||
"new_account_created_successfully": "Nieuwe rekening succesvol aangemaakt",
|
||||
"withdrew": "Opgenomen",
|
||||
"successfully": "Succesvol",
|
||||
"select_valid_account_and_amount": "Selecteer een geldige rekening en bedrag",
|
||||
"openBank": "Toegang tot Bank",
|
||||
"openATM": "Toegang tot Geldautomaat",
|
||||
"account_deletion_failed": "Verwijderen van rekening mislukt",
|
||||
"withdrawal_failed": "Opname mislukt",
|
||||
"deposit_failed": "Storting mislukt",
|
||||
"user_added_successfully": "Succesvol toegevoegd",
|
||||
"user_addition_failed": "Toevoegen van gebruiker mislukt",
|
||||
"new_account_creation_failed": "Aanmaken van nieuwe rekening mislukt",
|
||||
"account_renamed_successfully": "Rekening succesvol hernoemd",
|
||||
"account_rename_failed": "Hernoemen van rekening mislukt",
|
||||
"rename_account": "Naam wijzigen",
|
||||
"no_framework_found": "Geen framework gevonden",
|
||||
"cannot_send_self_money": "Je kunt geen geld naar jezelf sturen",
|
||||
"money_sent": "Je hebt %s naar %s gestuurd",
|
||||
"received_money": "Je hebt %s ontvangen van %s",
|
||||
"no_money": "Je hebt niet genoeg geld",
|
||||
"user_not_in_city": "Gebruiker is niet in de stad",
|
||||
"transaction_description": "Transactie",
|
||||
"cannot_add_self": "Je kunt jezelf niet toevoegen",
|
||||
"player_not_found": "Speler niet gevonden",
|
||||
"target_player_not_found": "Doelspeler niet gevonden",
|
||||
"user_already_in_account": "Gebruiker is reeds toegevoegd",
|
||||
"account_not_found": "Rekening niet gevonden"
|
||||
}
|
||||
|
139
resources/[tools]/ps-banking/locales/pt-br.json
Normal file
139
resources/[tools]/ps-banking/locales/pt-br.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "Caixa Eletrônico",
|
||||
"cash": "Dinheiro",
|
||||
"bank_balance": "Saldo Bancário",
|
||||
"deposit_amount": "Valor do Depósito",
|
||||
"withdraw_amount": "Valor do Saque",
|
||||
"submit": "Enviar",
|
||||
"close": "Fechar",
|
||||
"overview": "Visão Geral",
|
||||
"bills": "Contas",
|
||||
"history": "Histórico",
|
||||
"withdraw": "Sacar",
|
||||
"deposit": "Depositar",
|
||||
"stats": "Estatísticas",
|
||||
"transactions": "Transações",
|
||||
"transaction": "Transação",
|
||||
"total": "Total",
|
||||
"search_transactions": "Buscar transações...",
|
||||
"description": "Descrição",
|
||||
"type": "Tipo",
|
||||
"time_ago": "Tempo Atrás",
|
||||
"amount": "Valor",
|
||||
"date": "Data",
|
||||
"pay_invoice": "Pagar Fatura",
|
||||
"payment_completed": "Pagamento Concluído",
|
||||
"from": "De",
|
||||
"delete_all_transactions": "Excluir Todas as Transações",
|
||||
"are_you_sure": "Você tem certeza?",
|
||||
"delete_confirmation": "Você tem certeza que deseja excluir todas as suas transações? (Faça isso apenas se o menu estiver lento!)",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"history_empty": "Seu histórico está vazio",
|
||||
"all_history_deleted": "Você excluiu todo o seu histórico",
|
||||
"error": "Erro",
|
||||
"success": "Sucesso",
|
||||
"new_cash": "Novo Dinheiro",
|
||||
"withdraw_success": "Saque Bem-Sucedido",
|
||||
"withdraw_error": "Sua conta bancária não tem fundos suficientes",
|
||||
"withdraw_button": "SACAR",
|
||||
"new_bank": "Novo Saldo Bancário",
|
||||
"current_cash": "Dinheiro Atual",
|
||||
"deposit_success": "Depósito Bem-Sucedido",
|
||||
"deposit_error": "Você não tem dinheiro suficiente",
|
||||
"deposit_button": "DEPOSITAR",
|
||||
"total_balance": "Saldo Total",
|
||||
"quick_actions": "Ações Rápidas",
|
||||
"transfer_money": "Transferir Dinheiro",
|
||||
"easy_transfer": "Transfira dinheiro facilmente para pessoas",
|
||||
"transfer": "Transferir",
|
||||
"pay_bills": "Pagar Contas",
|
||||
"pay_pending_bills": "Pague rapidamente suas contas pendentes",
|
||||
"pay": "Pagar",
|
||||
"withdraw_all_money": "Sacar Todo o Dinheiro",
|
||||
"withdraw_all_from_account": "Sacar todo o dinheiro da sua conta",
|
||||
"deposit_cash": "Depositar Dinheiro",
|
||||
"deposit_all_cash": "Depositar todo o seu dinheiro na sua conta",
|
||||
"weekly_summary": "Resumo Semanal",
|
||||
"income": "Renda",
|
||||
"expenses": "Despesas",
|
||||
"report": "Relatório",
|
||||
"latest_transactions": "Últimas Transações",
|
||||
"see_all": "VER TUDO",
|
||||
"unpaid_bills": "Faturas Não Pagas",
|
||||
"no_unpaid_bills": "Nenhuma fatura não paga",
|
||||
"confirm_pay_all_bills": "Você tem certeza que deseja pagar todas as suas contas?",
|
||||
"pay_all_bills": "Pagar Todas as Contas",
|
||||
"pay_all_bills_success": "Você pagou todas as suas contas!",
|
||||
"pay_all_bills_error": "Você não tem contas",
|
||||
"payment_method": "Método de Pagamento",
|
||||
"phone_number": "Número de Telefone",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID ou Número de Telefone",
|
||||
"no_cash_on_you": "Você não tem dinheiro com você",
|
||||
"deposit_all_success": "Todo o seu dinheiro foi depositado",
|
||||
"no_money_on_account": "Sua conta está vazia",
|
||||
"withdraw_all_success": "Você sacou todo o dinheiro da conta",
|
||||
"invoices": "Faturas",
|
||||
"statistics_reports": "Estatísticas e Relatórios",
|
||||
"balance_trend": "Tendência do Saldo",
|
||||
"balance": "Saldo",
|
||||
"used": "Usado",
|
||||
"month": "Mês",
|
||||
"balance_dkk": "Saldo",
|
||||
"withdrawn": "Você sacou",
|
||||
"deposited": "Você depositou",
|
||||
"no_transactions": "Nenhuma transação recente",
|
||||
"transactions_trend": "Tendência das Transações",
|
||||
"total_transactions": "Total de Transações",
|
||||
"accounts": "Contas",
|
||||
"account_number_copied": "Número da conta copiado para a área de transferência",
|
||||
"new_user_to_account": "Novo usuário na conta",
|
||||
"server_id": "ID do Servidor",
|
||||
"add_user": "Adicionar Usuário",
|
||||
"new_account_name": "Novo Nome da Conta",
|
||||
"new_name": "Novo Nome",
|
||||
"rename": "Renomear",
|
||||
"create_new_account": "Criar Nova Conta",
|
||||
"account_holder": "Titular da Conta",
|
||||
"initial_balance": "Saldo Inicial",
|
||||
"create": "Criar",
|
||||
"delete_account": "Excluir Conta",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Você tem certeza que deseja excluir esta conta?",
|
||||
"delete": "Excluir",
|
||||
"remove_user_from_account": "Remover Usuário da Conta",
|
||||
"select_user": "Selecionar Usuário",
|
||||
"remove": "Remover",
|
||||
"withdraw_from_account": "Sacar da Conta",
|
||||
"deposit_to_account": "Depositar na Conta",
|
||||
"removed_successfully": "Removido com Sucesso",
|
||||
"select_account_and_user": "Por favor, selecione uma conta e um usuário",
|
||||
"account_deleted_successfully": "Conta excluída com sucesso",
|
||||
"new_account_created_successfully": "Nova conta criada com sucesso",
|
||||
"withdrew": "Sacou",
|
||||
"successfully": "Com Sucesso",
|
||||
"select_valid_account_and_amount": "Por favor, selecione uma conta e um valor válidos",
|
||||
"openBank": "Acessar Banco",
|
||||
"openATM": "Acessar Caixa Eletrônico",
|
||||
"account_deletion_failed": "Falha na exclusão da conta",
|
||||
"withdrawal_failed": "Falha no saque",
|
||||
"deposit_failed": "Falha no depósito",
|
||||
"user_added_successfully": "adicionado com sucesso",
|
||||
"user_addition_failed": "Falha ao adicionar usuário",
|
||||
"new_account_creation_failed": "Falha ao criar nova conta",
|
||||
"account_renamed_successfully": "Conta renomeada com sucesso",
|
||||
"account_rename_failed": "Falha ao renomear a conta",
|
||||
"rename_account": "Alterar nome",
|
||||
"no_framework_found": "Nenhum framework encontrado",
|
||||
"cannot_send_self_money": "Você não pode enviar dinheiro para si mesmo",
|
||||
"money_sent": "Você enviou %s para %s",
|
||||
"received_money": "Você recebeu %s de %s",
|
||||
"no_money": "Você não tem dinheiro suficiente",
|
||||
"user_not_in_city": "Usuário não está na cidade",
|
||||
"transaction_description": "Transação",
|
||||
"cannot_add_self": "Você não pode adicionar a si mesmo",
|
||||
"player_not_found": "Jogador não encontrado",
|
||||
"target_player_not_found": "Jogador alvo não encontrado",
|
||||
"user_already_in_account": "Usuário já está na conta",
|
||||
"account_not_found": "Conta não encontrada"
|
||||
}
|
139
resources/[tools]/ps-banking/locales/pt.json
Normal file
139
resources/[tools]/ps-banking/locales/pt.json
Normal file
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"atm": "Multibanco",
|
||||
"cash": "Dinheiro",
|
||||
"bank_balance": "Saldo Bancário",
|
||||
"deposit_amount": "Valor do Depósito",
|
||||
"withdraw_amount": "Valor do Levantamento",
|
||||
"submit": "Submeter",
|
||||
"close": "Fechar",
|
||||
"overview": "Visão Geral",
|
||||
"bills": "Faturas",
|
||||
"history": "Histórico",
|
||||
"withdraw": "Levantar",
|
||||
"deposit": "Depositar",
|
||||
"stats": "Estatísticas",
|
||||
"transactions": "Transações",
|
||||
"transaction": "Transação",
|
||||
"total": "Total",
|
||||
"search_transactions": "Pesquisar transações...",
|
||||
"description": "Descrição",
|
||||
"type": "Tipo",
|
||||
"time_ago": "Tempo Decorrido",
|
||||
"amount": "Montante",
|
||||
"date": "Data",
|
||||
"pay_invoice": "Pagar Fatura",
|
||||
"payment_completed": "Pagamento Concluído",
|
||||
"from": "De",
|
||||
"delete_all_transactions": "Eliminar Todas as Transações",
|
||||
"are_you_sure": "Tem a certeza?",
|
||||
"delete_confirmation": "Tem a certeza de que deseja eliminar todas as suas transações? (Faça-o apenas se o menu estiver lento!)",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar",
|
||||
"history_empty": "O seu histórico está vazio",
|
||||
"all_history_deleted": "Eliminou todo o seu histórico",
|
||||
"error": "Erro",
|
||||
"success": "Sucesso",
|
||||
"new_cash": "Novo Dinheiro",
|
||||
"withdraw_success": "Levantamento Bem-Sucedido",
|
||||
"withdraw_error": "A sua conta bancária não tem fundos suficientes",
|
||||
"withdraw_button": "LEVANTAR",
|
||||
"new_bank": "Novo Saldo Bancário",
|
||||
"current_cash": "Dinheiro Atual",
|
||||
"deposit_success": "Depósito Bem-Sucedido",
|
||||
"deposit_error": "Não tem dinheiro suficiente",
|
||||
"deposit_button": "DEPOSITAR",
|
||||
"total_balance": "Saldo Total",
|
||||
"quick_actions": "Ações Rápidas",
|
||||
"transfer_money": "Transferir Dinheiro",
|
||||
"easy_transfer": "Transfira dinheiro facilmente para outras pessoas",
|
||||
"transfer": "Transferir",
|
||||
"pay_bills": "Pagar Faturas",
|
||||
"pay_pending_bills": "Pague rapidamente as suas faturas pendentes",
|
||||
"pay": "Pagar",
|
||||
"withdraw_all_money": "Levantar Todo o Dinheiro",
|
||||
"withdraw_all_from_account": "Levantar todo o dinheiro da sua conta",
|
||||
"deposit_cash": "Depositar Dinheiro",
|
||||
"deposit_all_cash": "Depositar todo o seu dinheiro na sua conta",
|
||||
"weekly_summary": "Resumo Semanal",
|
||||
"income": "Rendimento",
|
||||
"expenses": "Despesas",
|
||||
"report": "Relatório",
|
||||
"latest_transactions": "Últimas Transações",
|
||||
"see_all": "VER TODAS",
|
||||
"unpaid_bills": "Faturas Não Pagas",
|
||||
"no_unpaid_bills": "Não tem faturas não pagas",
|
||||
"confirm_pay_all_bills": "Tem a certeza de que deseja pagar todas as suas faturas?",
|
||||
"pay_all_bills": "Pagar Todas as Faturas",
|
||||
"pay_all_bills_success": "Pagou todas as suas faturas!",
|
||||
"pay_all_bills_error": "Não tem faturas",
|
||||
"payment_method": "Método de Pagamento",
|
||||
"phone_number": "Número de Telefone",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID ou Número de Telefone",
|
||||
"no_cash_on_you": "Não tem dinheiro consigo",
|
||||
"deposit_all_success": "Todo o seu dinheiro foi depositado",
|
||||
"no_money_on_account": "A sua conta está vazia",
|
||||
"withdraw_all_success": "Levantou todo o dinheiro da conta",
|
||||
"invoices": "Faturas",
|
||||
"statistics_reports": "Estatísticas e Relatórios",
|
||||
"balance_trend": "Tendência do Saldo",
|
||||
"balance": "Saldo",
|
||||
"used": "Utilizado",
|
||||
"month": "Mês",
|
||||
"balance_dkk": "Saldo",
|
||||
"withdrawn": "Levantou",
|
||||
"deposited": "Depositou",
|
||||
"no_transactions": "Nenhuma transação recente",
|
||||
"transactions_trend": "Tendência das Transações",
|
||||
"total_transactions": "Total de Transações",
|
||||
"accounts": "Contas",
|
||||
"account_number_copied": "Número da conta copiado para a área de transferência",
|
||||
"new_user_to_account": "Novo utilizador na conta",
|
||||
"server_id": "ID do Servidor",
|
||||
"add_user": "Adicionar Utilizador",
|
||||
"new_account_name": "Novo Nome da Conta",
|
||||
"new_name": "Novo Nome",
|
||||
"rename": "Renomear",
|
||||
"create_new_account": "Criar Nova Conta",
|
||||
"account_holder": "Titular da Conta",
|
||||
"initial_balance": "Saldo Inicial",
|
||||
"create": "Criar",
|
||||
"delete_account": "Eliminar Conta",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Tem a certeza de que deseja eliminar esta conta?",
|
||||
"delete": "Eliminar",
|
||||
"remove_user_from_account": "Remover Utilizador da Conta",
|
||||
"select_user": "Selecionar Utilizador",
|
||||
"remove": "Remover",
|
||||
"withdraw_from_account": "Levantar da Conta",
|
||||
"deposit_to_account": "Depositar na Conta",
|
||||
"removed_successfully": "Removido com Sucesso",
|
||||
"select_account_and_user": "Por favor, selecione uma conta e um utilizador",
|
||||
"account_deleted_successfully": "Conta eliminada com sucesso",
|
||||
"new_account_created_successfully": "Nova conta criada com sucesso",
|
||||
"withdrew": "Levantou",
|
||||
"successfully": "com sucesso",
|
||||
"select_valid_account_and_amount": "Por favor, selecione uma conta e um montante válido",
|
||||
"openBank": "Aceder ao Banco",
|
||||
"openATM": "Aceder ao Multibanco",
|
||||
"account_deletion_failed": "Falha na eliminação da conta",
|
||||
"withdrawal_failed": "Falha no levantamento",
|
||||
"deposit_failed": "Falha no depósito",
|
||||
"user_added_successfully": "adicionado com sucesso",
|
||||
"user_addition_failed": "Falha ao adicionar utilizador",
|
||||
"new_account_creation_failed": "Falha ao criar nova conta",
|
||||
"account_renamed_successfully": "Conta renomeada com sucesso",
|
||||
"account_rename_failed": "Falha ao renomear a conta",
|
||||
"rename_account": "Alterar nome",
|
||||
"no_framework_found": "Nenhum framework encontrado",
|
||||
"cannot_send_self_money": "Não pode enviar dinheiro para si mesmo",
|
||||
"money_sent": "Enviou %s para %s",
|
||||
"received_money": "Recebeu %s de %s",
|
||||
"no_money": "Não tem dinheiro suficiente",
|
||||
"user_not_in_city": "Utilizador não está na cidade",
|
||||
"transaction_description": "Transação",
|
||||
"cannot_add_self": "Não pode adicionar a si mesmo",
|
||||
"player_not_found": "Jogador não encontrado",
|
||||
"target_player_not_found": "Jogador alvo não encontrado",
|
||||
"user_already_in_account": "Utilizador já está na conta",
|
||||
"account_not_found": "Conta não encontrada"
|
||||
}
|
140
resources/[tools]/ps-banking/locales/tr.json
Normal file
140
resources/[tools]/ps-banking/locales/tr.json
Normal file
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"atm": "ATM",
|
||||
"cash": "Nakit",
|
||||
"bank_balance": "Banka Bakiyesi",
|
||||
"deposit_amount": "Para Yatırma Miktarı",
|
||||
"withdraw_amount": "Para Çekme Miktarı",
|
||||
"submit": "Gönder",
|
||||
"close": "Kapat",
|
||||
"overview": "Görünüm",
|
||||
"bills": "Faturalar",
|
||||
"history": "Geçmiş",
|
||||
"withdraw": "Para Çekme",
|
||||
"deposit": "Para Yatırma",
|
||||
"stats": "İstatistikler",
|
||||
"transactions": "İşlemler",
|
||||
"transaction": "İşlem",
|
||||
"total": "Toplam",
|
||||
"search_transactions": "İşlemleri ara...",
|
||||
"description": "Açıklama",
|
||||
"type": "Tip",
|
||||
"time_ago": "Zaman Önce",
|
||||
"amount": "Miktar",
|
||||
"date": "Tarih",
|
||||
"pay_invoice": "Fatura Öde",
|
||||
"payment_completed": "Ödeme Tamamlandı",
|
||||
"from": "Tarafından",
|
||||
"delete_all_transactions": "Tüm Ödemeleri Sil",
|
||||
"are_you_sure": "Emin misiniz?",
|
||||
"delete_confirmation": "Tüm ödemeleri silmek istediğinizden emin misiniz? (Lütfen bunu sadece menü gecikmeleri oluyorsa yapın!)",
|
||||
"cancel": "İptal",
|
||||
"confirm": "Onayla",
|
||||
"history_empty": "Geçmişiniz boş",
|
||||
"all_history_deleted": "Tüm geçmişinizi sildiniz",
|
||||
"error": "Hata",
|
||||
"success": "Başarılı",
|
||||
"new_cash": "Yeni Nakit",
|
||||
"withdraw_success": "Para Çekme Başarılı",
|
||||
"withdraw_error": "Banka hesabınızda yeterli bakiye yok",
|
||||
"withdraw_button": "PARA ÇEK",
|
||||
"new_bank": "Yeni Banka Bakiyesi",
|
||||
"current_cash": "Mevcut Nakit",
|
||||
"deposit_success": "Para Yatırma Başarılı",
|
||||
"deposit_error": "Yeterli nakitiniz yok",
|
||||
"deposit_button": "PARA YATIR",
|
||||
"total_balance": "Toplam Bakiye",
|
||||
"quick_actions": "Hızlı İşlemler",
|
||||
"transfer_money": "Para Transferi",
|
||||
"easy_transfer": "İnsanlara kolayca para aktarın",
|
||||
"transfer": "Transfer",
|
||||
"pay_bills": "Faturaları Öde",
|
||||
"pay_pending_bills": "Bekleyen faturalarınızı hızlıca ödeyin",
|
||||
"pay": "Öde",
|
||||
"withdraw_all_money": "Tüm Paranızı Çekin",
|
||||
"withdraw_all_from_account": "Hesabınızda bulunan tüm parayı çekin",
|
||||
"deposit_cash": "Nakit Yatır",
|
||||
"deposit_all_cash": "Tüm paranızı hesabınıza yatırın",
|
||||
"weekly_summary": "Haftalık Özet",
|
||||
"income": "Gelir",
|
||||
"expenses": "Masraflar",
|
||||
"report": "Rapor",
|
||||
"latest_transactions": "Son İşlemler",
|
||||
"see_all": "TÜMÜNÜ GÖSTER",
|
||||
"unpaid_bills": "Ödenmemiş Faturalar",
|
||||
"no_unpaid_bills": "Ödenmemiş faturanız yok",
|
||||
"confirm_pay_all_bills": "Tüm faturalarınızı ödemek istediğinizden emin misiniz?",
|
||||
"pay_all_bills": "Tüm Faturaları Öde",
|
||||
"pay_all_bills_success": "Tüm faturalarınızı ödediniz!",
|
||||
"pay_all_bills_error": "Size kesilen bir fatura yok",
|
||||
"payment_method": "Ödeme Yöntemi",
|
||||
"phone_number": "Telefon Numarası",
|
||||
"id": "ID",
|
||||
"id_or_phone_number": "ID veya Telefon Numarası",
|
||||
"no_cash_on_you": "Üzerinizde nakit yok",
|
||||
"deposit_all_success": "Tüm paranız yatırıldı",
|
||||
"no_money_on_account": "Hesabınızda para yok",
|
||||
"withdraw_all_success": "Hesabınızdaki tüm parayı çektiniz",
|
||||
"invoices": "Faturalar",
|
||||
"statistics_reports": "İstatistikler ve Raporlar",
|
||||
"balance_trend": "Denge Trendi",
|
||||
"balance": "Denge",
|
||||
"used": "Kullanıldı",
|
||||
"month": "Ay",
|
||||
"balance_dkk": "Balance",
|
||||
"withdrawn": "Para çektiniz",
|
||||
"deposited": "Para yatırdınız",
|
||||
"no_transactions": "Son işlemler yok",
|
||||
"transactions_trend": "Transactions Trend",
|
||||
"total_transactions": "Toplam İşlemler",
|
||||
"accounts": "Hesaplar",
|
||||
"account_number_copied": "Hesap numarası panonuza kopyalandı",
|
||||
"new_user_to_account": "Hesabınıza yeni kullanıcı",
|
||||
"server_id": "Sunucu ID",
|
||||
"add_user": "Kullanıcı Ekle",
|
||||
"new_account_name": "Yeni Hesap İsmi",
|
||||
"new_name": "Yeni İsim",
|
||||
"rename": "Yeniden Adlandır",
|
||||
"create_new_account": "Yeni Hesap Oluştur",
|
||||
"account_holder": "Hesap Sahibi",
|
||||
"initial_balance": "Başlangıç Bakiyesi",
|
||||
"create": "Oluştur",
|
||||
"delete_account": "Hesabı Sil",
|
||||
"are_you_sure_you_want_to_delete_this_account": "Bu hesabı silmek istediğinizden emin misiniz?",
|
||||
"delete": "Sil",
|
||||
"remove_user_from_account": "Hesaptan Kullanıcı Kaldır",
|
||||
"select_user": "Kullanıcı Seç",
|
||||
"remove": "Kaldır",
|
||||
"withdraw_from_account": "Hesaptan Para Çekme",
|
||||
"deposit_to_account": "Hesaba Para Yatırmak",
|
||||
"removed_successfully": "Başarıyla Kaldırıldı",
|
||||
"select_account_and_user": "Lütfen hesap ve kullanıcı seçin",
|
||||
"account_deleted_successfully": "Hesap başarıyla kaldırıldı",
|
||||
"new_account_created_successfully": "Yeni hesap başarıyla oluşturuldu",
|
||||
"withdrew": "Çekildi",
|
||||
"successfully": "Başarılı",
|
||||
"select_valid_account_and_amount": "Lütfen geçerli bir hesap ve tutar seçin",
|
||||
"openBank": "Bankaya Eriş",
|
||||
"openATM": "ATM'e Eriş",
|
||||
"account_deletion_failed": "Hesap silme işlemi başarısız oldu",
|
||||
"withdrawal_failed": "Para çekme işlemi başarısız oldu",
|
||||
"deposit_failed": "Para yatırma işlemi başarısız oldu",
|
||||
"user_added_successfully": "Kullanıcı başarıyla eklendi",
|
||||
"user_addition_failed": "Kullanıcı ekleme başarısız oldu",
|
||||
"new_account_creation_failed": "Yeni hesap oluşturma işlemi başarısız oldu",
|
||||
"account_renamed_successfully": "Hesap başarıyla yeniden adlandırıldı",
|
||||
"account_rename_failed": "Hesap yeniden adlandırma işlemi başarısız oldu",
|
||||
"rename_account": "İsmi değiştir",
|
||||
"no_framework_found": "Geçerli bir framework bulunamadı",
|
||||
"cannot_send_self_money": "Kendinize para gönderemezsiniz",
|
||||
"money_sent": "%s kişisine %s tutar gönderildi",
|
||||
"received_money": "%s miktar parayı %s kişisinden aldınız",
|
||||
"no_money": "Yeterli miktarda paranız bulunmuyor",
|
||||
"user_not_in_city": "Kullanıcı şehirde değil",
|
||||
"transaction_description": "İşlem",
|
||||
"cannot_add_self": "Kendinize ekleyemezsiniz",
|
||||
"player_not_found": "Oyuncu bulunamadı",
|
||||
"target_player_not_found": "Hedef oyuncu bulunamadı",
|
||||
"user_already_in_account": "Kullanıcı zaten hesapta bulunuyor",
|
||||
"account_not_found": "Hesap bulunamadı"
|
||||
}
|
||||
|
54
resources/[tools]/ps-banking/ps-banking.sql
Normal file
54
resources/[tools]/ps-banking/ps-banking.sql
Normal file
|
@ -0,0 +1,54 @@
|
|||
CREATE TABLE
|
||||
`ps_banking_transactions` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`identifier` VARCHAR(50) NOT NULL,
|
||||
`description` VARCHAR(255) NOT NULL,
|
||||
`type` VARCHAR(50) NOT NULL,
|
||||
`amount` DECIMAL(10, 2) NOT NULL,
|
||||
`date` DATE NOT NULL,
|
||||
`isIncome` BOOLEAN NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
CREATE TABLE
|
||||
`ps_banking_bills` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`identifier` VARCHAR(50) NOT NULL,
|
||||
`description` VARCHAR(255) NOT NULL,
|
||||
`type` VARCHAR(50) NOT NULL,
|
||||
`amount` DECIMAL(10, 2) NOT NULL,
|
||||
`date` DATE NOT NULL,
|
||||
`isPaid` BOOLEAN NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
CREATE TABLE
|
||||
`ps_banking_accounts` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`balance` BIGINT NOT NULL,
|
||||
`holder` VARCHAR(255) NOT NULL,
|
||||
`cardNumber` VARCHAR(255) NOT NULL,
|
||||
`users` JSON NOT NULL,
|
||||
`owner` JSON NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
|
||||
|
||||
/* Dummy data (Ignore)
|
||||
INSERT INTO `ps_banking_bills` (`identifier`, `description`, `type`, `amount`, `date`, `isPaid`) VALUES
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Utility Bill', 'Expense', 150.00, '2024-07-20', 0);
|
||||
|
||||
INSERT INTO `ps_banking_transactions` (`identifier`, `description`, `type`, `amount`, `date`, `isIncome`) VALUES
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Opened a new account', 'From account', 1000.00, '2022-08-13', 0),
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Deposited 500 DKK to account', 'To account', 500.00, '2022-08-13', 1),
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Deposited 500 DKK to account', 'To account', 500.00, '2022-08-13', 1),
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Withdrew 500 DKK from ATM', 'From account', -500.00, '2022-08-13', 0),
|
||||
('char1:df6c12c50e2712c57b1386e7103d5a372fb960a0', 'Deposited 500 DKK to account', 'To account', 500.00, '2022-08-13', 1),
|
||||
('char2:ab12c34d5e67f89g01234h56789i012j34kl567m8', 'Opened a new account', 'From account', 2000.00, '2022-08-14', 0),
|
||||
('char2:ab12c34d5e67f89g01234h56789i012j34kl567m8', 'Deposited 1000 DKK to account', 'To account', 1000.00, '2022-08-14', 1),
|
||||
('char2:ab12c34d5e67f89g01234h56789i012j34kl567m8', 'Withdrew 300 DKK from ATM', 'From account', -300.00, '2022-08-14', 0),
|
||||
('char2:ab12c34d5e67f89g01234h56789i012j34kl567m8', 'Deposited 400 DKK to account', 'To account', 400.00, '2022-08-14', 1),
|
||||
('char2:ab12c34d5e67f89g01234h56789i012j34kl567m8', 'Withdrew 200 DKK from ATM', 'From account', -200.00, '2022-08-14', 0);
|
||||
|
||||
*/
|
458
resources/[tools]/ps-banking/server/main.lua
Normal file
458
resources/[tools]/ps-banking/server/main.lua
Normal file
|
@ -0,0 +1,458 @@
|
|||
lib.versionCheck('Project-Sloth/ps-banking')
|
||||
assert(lib.checkDependency('ox_lib', '3.20.0', true))
|
||||
|
||||
local framework = nil
|
||||
|
||||
if GetResourceState("es_extended") == "started" then
|
||||
framework = "ESX"
|
||||
ESX = exports["es_extended"]:getSharedObject()
|
||||
elseif GetResourceState("qb-core") == "started" then
|
||||
framework = "QBCore"
|
||||
QBCore = exports["qb-core"]:GetCoreObject()
|
||||
else
|
||||
return error(locale("no_framework_found"))
|
||||
end
|
||||
|
||||
local function getPlayerIdentifier(player)
|
||||
if framework == "ESX" then
|
||||
return player.getIdentifier()
|
||||
elseif framework == "QBCore" then
|
||||
return player.PlayerData.citizenid
|
||||
end
|
||||
end
|
||||
|
||||
local function getPlayerFromId(source)
|
||||
if framework == "ESX" then
|
||||
return ESX.GetPlayerFromId(source)
|
||||
elseif framework == "QBCore" then
|
||||
return QBCore.Functions.GetPlayer(source)
|
||||
end
|
||||
end
|
||||
|
||||
local function getPlayerAccounts(player)
|
||||
if framework == "ESX" then
|
||||
return player.getAccount("bank").money
|
||||
elseif framework == "QBCore" then
|
||||
return player.PlayerData.money["bank"]
|
||||
end
|
||||
end
|
||||
|
||||
local function getName(player)
|
||||
if framework == "ESX" then
|
||||
return player.getName()
|
||||
elseif framework == "QBCore" then
|
||||
return player.PlayerData.charinfo.firstname .. " " .. player.PlayerData.charinfo.lastname
|
||||
end
|
||||
end
|
||||
|
||||
lib.callback.register("ps-banking:server:getHistory", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
local result = MySQL.query.await('SELECT * FROM ps_banking_transactions WHERE identifier = ?', { identifier })
|
||||
return result
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:deleteHistory", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
MySQL.query.await('DELETE FROM ps_banking_transactions WHERE identifier = ?', { identifier })
|
||||
return true
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:payAllBills", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
local result = MySQL.query.await('SELECT SUM(amount) as total FROM ps_banking_bills WHERE identifier = ? AND isPaid = 0', { identifier })
|
||||
local totalAmount = result[1].total or 0
|
||||
local bankBalance = getPlayerAccounts(xPlayer)
|
||||
if tonumber(bankBalance) >= tonumber(totalAmount) then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeAccountMoney("bank", tonumber(totalAmount))
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("bank", tonumber(totalAmount))
|
||||
end
|
||||
MySQL.query.await('DELETE FROM ps_banking_bills WHERE identifier = ?', { identifier })
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:getWeeklySummary", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
local receivedResult = MySQL.query.await('SELECT SUM(amount) as totalReceived FROM ps_banking_transactions WHERE identifier = ? AND isIncome = ? AND DATE(date) >= DATE(NOW() - INTERVAL 7 DAY)', { identifier, true })
|
||||
local totalReceived = receivedResult[1].totalReceived or 0
|
||||
local usedResult = MySQL.query.await('SELECT SUM(amount) as totalUsed FROM ps_banking_transactions WHERE identifier = ? AND isIncome = ? AND DATE(date) >= DATE(NOW() - INTERVAL 7 DAY)', { identifier, false })
|
||||
local totalUsed = usedResult[1].totalUsed or 0
|
||||
return {
|
||||
totalReceived = totalReceived,
|
||||
totalUsed = totalUsed,
|
||||
}
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:transferMoney", function(source, data)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local targetPlayer = getPlayerFromId(data.id)
|
||||
local amount = tonumber(data.amount)
|
||||
|
||||
if data.id == source and data.method == "id" then
|
||||
return false, locale("cannot_send_self_money")
|
||||
end
|
||||
|
||||
if xPlayer and targetPlayer and amount > 0 then
|
||||
local xPlayerBalance = getPlayerAccounts(xPlayer)
|
||||
if xPlayerBalance >= amount then
|
||||
if data.method == "id" then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeAccountMoney("bank", amount)
|
||||
targetPlayer.addAccountMoney("bank", amount)
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("bank", amount)
|
||||
targetPlayer.Functions.AddMoney("bank", amount)
|
||||
end
|
||||
return true, locale("money_sent", amount, getName(targetPlayer))
|
||||
elseif data.method == "phone" then
|
||||
exports["lb-phone"]:AddTransaction(targetPlayer.identifier, amount,
|
||||
locale("received_money", getName(xPlayer), amount))
|
||||
return true, locale("money_sent", amount, getName(targetPlayer))
|
||||
end
|
||||
else
|
||||
return false, locale("no_money")
|
||||
end
|
||||
else
|
||||
return false, locale("user_not_in_city")
|
||||
end
|
||||
end)
|
||||
|
||||
local function logTransaction(identifier, description, accountName, amount, isIncome)
|
||||
MySQL.insert.await('INSERT INTO ps_banking_transactions (identifier, description, type, amount, date, isIncome) VALUES (?, ?, ?, ?, NOW(), ?)', { identifier, description, accountName, amount, isIncome })
|
||||
end
|
||||
|
||||
RegisterNetEvent("ps-banking:server:logClient", function(account, moneyData)
|
||||
if account.name ~= "bank" then
|
||||
return
|
||||
end
|
||||
|
||||
local src = source
|
||||
local xPlayer = getPlayerFromId(src)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
|
||||
local previousBankBalance = 0
|
||||
if moneyData then
|
||||
for _, data in ipairs(moneyData) do
|
||||
if data.name == "bank" then
|
||||
previousBankBalance = data.amount
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local currentBankBalance = getPlayerAccounts(xPlayer)
|
||||
local amountChange = currentBankBalance - previousBankBalance
|
||||
|
||||
if amountChange ~= 0 then
|
||||
local isIncome = currentBankBalance >= previousBankBalance and true or false
|
||||
local description = locale("transaction_description")
|
||||
logTransaction(identifier, description, account.name, math.abs(amountChange), isIncome)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
lib.callback.register("ps-banking:server:getTransactionStats", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
|
||||
local result = MySQL.query.await('SELECT COUNT(*) as totalCount, SUM(amount) as totalAmount FROM ps_banking_transactions WHERE identifier = ?', { identifier })
|
||||
local transactionData = MySQL.query.await('SELECT amount, date FROM ps_banking_transactions WHERE identifier = ? ORDER BY date DESC LIMIT 50', { identifier })
|
||||
|
||||
return {
|
||||
totalCount = result[1].totalCount,
|
||||
totalAmount = result[1].totalAmount,
|
||||
transactionData = transactionData,
|
||||
}
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:createNewAccount", function(source, newAccount)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
MySQL.insert.await('INSERT INTO ps_banking_accounts (balance, holder, cardNumber, users, owner) VALUES (?, ?, ?, ?, ?)', { newAccount.balance, newAccount.holder, newAccount.cardNumber, json.encode(newAccount.users), json.encode(newAccount.owner) })
|
||||
return true
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:getUser", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
return {
|
||||
name = getName(xPlayer),
|
||||
identifier = getPlayerIdentifier(xPlayer),
|
||||
}
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:getAccounts", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
local playerIdentifier = getPlayerIdentifier(xPlayer)
|
||||
local accounts = MySQL.query.await('SELECT * FROM ps_banking_accounts')
|
||||
local result = {}
|
||||
for _, account in ipairs(accounts) do
|
||||
local accountData = {
|
||||
id = account.id,
|
||||
balance = account.balance,
|
||||
holder = account.holder,
|
||||
cardNumber = account.cardNumber,
|
||||
users = json.decode(account.users),
|
||||
owner = json.decode(account.owner),
|
||||
}
|
||||
if accountData.owner.identifier == playerIdentifier then
|
||||
accountData.owner.state = true
|
||||
table.insert(result, accountData)
|
||||
else
|
||||
for _, user in ipairs(accountData.users) do
|
||||
if user.identifier == playerIdentifier then
|
||||
accountData.owner.state = false
|
||||
table.insert(result, accountData)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:deleteAccount", function(source, accountId)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
|
||||
MySQL.query.await('DELETE FROM ps_banking_accounts WHERE id = ?', { accountId })
|
||||
return true
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:withdrawFromAccount", function(source, accountId, amount)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
local account = MySQL.query.await('SELECT * FROM ps_banking_accounts WHERE id = ?', { accountId })
|
||||
if #account > 0 then
|
||||
local balance = account[1].balance
|
||||
if balance >= amount then
|
||||
local affectedRows = MySQL.update.await('UPDATE ps_banking_accounts SET balance = balance - ? WHERE id = ?', { amount, accountId })
|
||||
if affectedRows > 0 then
|
||||
if framework == "ESX" then
|
||||
xPlayer.addAccountMoney("bank", amount)
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.AddMoney("bank", amount)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:depositToAccount", function(source, accountId, amount)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
if getPlayerAccounts(xPlayer) >= amount then
|
||||
local affectedRows = MySQL.update.await('UPDATE ps_banking_accounts SET balance = balance + ? WHERE id = ?', { amount, accountId })
|
||||
if affectedRows > 0 then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeAccountMoney("bank", amount)
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("bank", amount)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:addUserToAccount", function(source, accountId, userId)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local targetPlayer = getPlayerFromId(userId)
|
||||
local promise = promise.new()
|
||||
if source == userId then
|
||||
return {
|
||||
success = false,
|
||||
message = locale("cannot_add_self"),
|
||||
}
|
||||
end
|
||||
if not xPlayer then
|
||||
return {
|
||||
success = false,
|
||||
message = locale("player_not_found"),
|
||||
}
|
||||
end
|
||||
if not targetPlayer then
|
||||
return {
|
||||
success = false,
|
||||
message = locale("target_player_not_found"),
|
||||
}
|
||||
end
|
||||
local accounts = MySQL.query.await('SELECT * FROM ps_banking_accounts WHERE id = ?', { accountId })
|
||||
if #accounts > 0 then
|
||||
local account = accounts[1]
|
||||
local users = json.decode(account.users)
|
||||
for _, user in ipairs(users) do
|
||||
if user.identifier == userId then
|
||||
return {
|
||||
success = false,
|
||||
message = locale("user_already_in_account"),
|
||||
}
|
||||
end
|
||||
end
|
||||
table.insert(users, {
|
||||
name = getName(targetPlayer),
|
||||
identifier = getPlayerIdentifier(targetPlayer),
|
||||
})
|
||||
local affectedRows = MySQL.update.await('UPDATE ps_banking_accounts SET users = ? WHERE id = ?', { json.encode(users), accountId })
|
||||
return {
|
||||
success = affectedRows > 0,
|
||||
userName = getName(targetPlayer),
|
||||
}
|
||||
else
|
||||
return {
|
||||
success = false,
|
||||
message = locale("account_not_found"),
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:removeUserFromAccount", function(source, accountId, userId)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
local accounts = MySQL.query.await('SELECT * FROM ps_banking_accounts WHERE id = ?', { accountId })
|
||||
if #accounts > 0 then
|
||||
local account = accounts[1]
|
||||
local users = json.decode(account.users)
|
||||
local updatedUsers = {}
|
||||
for _, user in ipairs(users) do
|
||||
if user.identifier ~= userId then
|
||||
table.insert(updatedUsers, user)
|
||||
end
|
||||
end
|
||||
local affectedRows = MySQL.update.await('UPDATE ps_banking_accounts SET users = ? WHERE id = ?', { json.encode(updatedUsers), accountId })
|
||||
return affectedRows > 0
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:renameAccount", function(source, id, newName)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
if not xPlayer then
|
||||
return false
|
||||
end
|
||||
local affectedRows = MySQL.update.await('UPDATE ps_banking_accounts SET holder = ? WHERE id = ?', { newName, id })
|
||||
return affectedRows > 0
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:ATMwithdraw", function(source, amount)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local bankBalance = getPlayerAccounts(xPlayer)
|
||||
|
||||
if bankBalance >= amount then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeAccountMoney("bank", amount)
|
||||
xPlayer.addMoney(amount)
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("bank", amount)
|
||||
xPlayer.Functions.AddMoney("cash", amount)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:ATMdeposit", function(source, amount)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local cashBalance = nil
|
||||
if framework == "ESX" then
|
||||
cashBalance = xPlayer.getMoney()
|
||||
elseif framework == "QBCore" then
|
||||
cashBalance = xPlayer.PlayerData.money["cash"]
|
||||
end
|
||||
|
||||
if cashBalance >= amount then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeMoney(amount)
|
||||
xPlayer.addAccountMoney("bank", amount)
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("cash", amount)
|
||||
xPlayer.Functions.AddMoney("bank", amount)
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:getBills", function(source)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
local result = MySQL.query.await('SELECT * FROM ps_banking_bills WHERE identifier = ?', { identifier })
|
||||
return result
|
||||
end)
|
||||
|
||||
lib.callback.register("ps-banking:server:payBill", function(source, billId)
|
||||
local xPlayer = getPlayerFromId(source)
|
||||
local identifier = getPlayerIdentifier(xPlayer)
|
||||
local result = MySQL.query.await('SELECT * FROM ps_banking_bills WHERE id = ? AND identifier = ? AND isPaid = 0', { billId, identifier })
|
||||
if #result == 0 then
|
||||
return false
|
||||
end
|
||||
local bill = result[1]
|
||||
local amount = bill.amount
|
||||
if tonumber(getPlayerAccounts(xPlayer)) >= tonumber(amount) then
|
||||
if framework == "ESX" then
|
||||
xPlayer.removeAccountMoney("bank", tonumber(amount))
|
||||
elseif framework == "QBCore" then
|
||||
xPlayer.Functions.RemoveMoney("bank", tonumber(amount))
|
||||
end
|
||||
MySQL.query.await('DELETE FROM ps_banking_bills WHERE id = ?', { billId })
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
function createBill(data)
|
||||
local identifier = data.identifier
|
||||
local description = data.description
|
||||
local type = data.type
|
||||
local amount = data.amount
|
||||
|
||||
MySQL.insert.await('INSERT INTO ps_banking_bills (identifier, description, type, amount, date, isPaid) VALUES (?, ?, ?, ?, NOW(), ?)', { identifier, description, type, amount, false })
|
||||
end
|
||||
exports("createBill", createBill)
|
||||
|
||||
--[[ EXAMPLE
|
||||
exports["ps-banking"]:createBill({
|
||||
identifier = "char1:df6c12c50e2712c57b1386e7103d5a372fb960a0",
|
||||
description = "Utility Bill",
|
||||
type = "Expense",
|
||||
amount = 150.00,
|
||||
})
|
||||
]]
|
24
resources/[tools]/ps-banking/web/.gitignore
vendored
Normal file
24
resources/[tools]/ps-banking/web/.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
48
resources/[tools]/ps-banking/web/index.html
Normal file
48
resources/[tools]/ps-banking/web/index.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bach Banking</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/all.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-duotone-solid.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-thin.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-solid.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-regular.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://site-assets.fontawesome.com/releases/v6.6.0/css/sharp-light.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<style>
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
::-webkit-outer-spin-button,
|
||||
::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
3613
resources/[tools]/ps-banking/web/package-lock.json
generated
Normal file
3613
resources/[tools]/ps-banking/web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
48
resources/[tools]/ps-banking/web/package.json
Normal file
48
resources/[tools]/ps-banking/web/package.json
Normal file
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev:game": "vite build --watch",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||
"@tsconfig/svelte": "^5.0.4",
|
||||
"@types/d3-interpolate": "^3.0.4",
|
||||
"@types/d3-scale": "^4.0.8",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-shape": "^3.1.6",
|
||||
"@types/d3-transition": "^3.0.8",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-load-config": "^5.0.3",
|
||||
"svelte": "^4.2.12",
|
||||
"svelte-check": "^3.6.9",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.4.3",
|
||||
"vite": "^4.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@rollup/plugin-dsv": "^3.0.4",
|
||||
"apexcharts": "^3.48.0",
|
||||
"bits-ui": "^0.21.10",
|
||||
"chart.js": "^3.9.1",
|
||||
"d3": "^7.9.0",
|
||||
"d3-scale": "^4.0.2",
|
||||
"layercake": "^8.1.1",
|
||||
"lucide-svelte": "^0.368.0",
|
||||
"svelte-apexcharts": "^1.0.2",
|
||||
"svelte-chartjs": "^3.1.5",
|
||||
"svelte-fa": "^4.0.2",
|
||||
"svelte-radix": "^1.1.0"
|
||||
}
|
||||
}
|
1805
resources/[tools]/ps-banking/web/pnpm-lock.yaml
generated
Normal file
1805
resources/[tools]/ps-banking/web/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
13
resources/[tools]/ps-banking/web/postcss.config.cjs
Normal file
13
resources/[tools]/ps-banking/web/postcss.config.cjs
Normal file
|
@ -0,0 +1,13 @@
|
|||
const tailwindcss = require("tailwindcss");
|
||||
const autoprefixer = require("autoprefixer");
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
autoprefixer,
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
58
resources/[tools]/ps-banking/web/src/App.svelte
Normal file
58
resources/[tools]/ps-banking/web/src/App.svelte
Normal file
|
@ -0,0 +1,58 @@
|
|||
<script lang="ts">
|
||||
import VisibilityProvider from "./providers/VisibilityProvider.svelte";
|
||||
import Main from "./components/Main.svelte";
|
||||
import { debugData } from "./utils/debugData";
|
||||
import { slide, fade } from "svelte/transition";
|
||||
import { notifications, showATM } from "../src/store/data";
|
||||
import { visibility } from "../src/store/stores";
|
||||
|
||||
debugData([
|
||||
{
|
||||
action: "openBank",
|
||||
data: true,
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<VisibilityProvider>
|
||||
<Main />
|
||||
</VisibilityProvider>
|
||||
{#if $showATM}
|
||||
<div
|
||||
class="absolute bottom-44 right-[22%] grid grid-cols-1 gap-2 select-none"
|
||||
>
|
||||
{#each $notifications as notification (notification.id)}
|
||||
<div
|
||||
class="bg-gray-900 text-blue-200 py-3 px-6 rounded-lg shadow-xl flex items-center space-x-3 transform transition-transform duration-500 border border-gray-700/50"
|
||||
in:slide={{ duration: 300 }}
|
||||
out:fade={{ duration: 300 }}
|
||||
>
|
||||
<i class="fa-duotone fa-{notification.icon} text-2xl"></i>
|
||||
<div>
|
||||
<p class="font-bold">{notification.title}</p>
|
||||
<p>{notification.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="absolute bottom-24 right-[12%] grid grid-cols-1 gap-2 select-none"
|
||||
>
|
||||
{#each $notifications as notification (notification.id)}
|
||||
<div
|
||||
class="bg-gray-900 text-blue-200 py-3 px-6 rounded-lg shadow-xl flex items-center space-x-3 transform transition-transform duration-500 border border-gray-700/50"
|
||||
in:slide={{ duration: 300 }}
|
||||
out:fade={{ duration: 300 }}
|
||||
>
|
||||
<i class="fa-duotone fa-{notification.icon} text-2xl"></i>
|
||||
<div>
|
||||
<p class="font-bold">{notification.title}</p>
|
||||
<p>{notification.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</main>
|
3
resources/[tools]/ps-banking/web/src/app.pcss
Normal file
3
resources/[tools]/ps-banking/web/src/app.pcss
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
272
resources/[tools]/ps-banking/web/src/components/ATM.svelte
Normal file
272
resources/[tools]/ps-banking/web/src/components/ATM.svelte
Normal file
|
@ -0,0 +1,272 @@
|
|||
<script lang="ts">
|
||||
import { writable, get } from "svelte/store";
|
||||
import { onMount } from "svelte";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { slide, fade, scale } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import {
|
||||
showATM,
|
||||
currentCash,
|
||||
bankBalance,
|
||||
Notify,
|
||||
type Notification,
|
||||
Locales,
|
||||
Currency,
|
||||
} from "../store/data";
|
||||
|
||||
let customWithdraw = writable(0);
|
||||
let customDeposit = writable(0);
|
||||
let withdrawAmounts = writable([]);
|
||||
let depositAmounts = writable([]);
|
||||
let gridColsPreset = writable(3);
|
||||
|
||||
$: (customDeposit = currentCash), (customWithdraw = bankBalance);
|
||||
|
||||
async function getAmountPresets() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getAmountPresets", {});
|
||||
const amounts = JSON.parse(response);
|
||||
withdrawAmounts.set(amounts.withdrawAmounts);
|
||||
depositAmounts.set(amounts.depositAmounts);
|
||||
gridColsPreset.set(amounts.grid);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateBalances() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getMoneyTypes", {});
|
||||
const bank = response.find(
|
||||
(item: { name: string }) => item.name === "bank"
|
||||
);
|
||||
const cash = response.find(
|
||||
(item: { name: string }) => item.name === "cash"
|
||||
);
|
||||
if (bank) {
|
||||
bankBalance.set(bank.amount);
|
||||
}
|
||||
if (cash) {
|
||||
currentCash.set(cash.amount);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function heav(amount: number) {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:ATMwithdraw", {
|
||||
amount: amount,
|
||||
});
|
||||
if (response) {
|
||||
Notify(
|
||||
`${$Locales.withdrawn} ${amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}`,
|
||||
$Locales.payment_completed,
|
||||
"coins"
|
||||
);
|
||||
await updateBalances();
|
||||
} else {
|
||||
Notify($Locales.no_money_on_account, $Locales.error, "credit-card");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deposit(amount: number) {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:ATMdeposit", {
|
||||
amount: amount,
|
||||
});
|
||||
if (response) {
|
||||
Notify(
|
||||
`${$Locales.deposited} ${amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}`,
|
||||
$Locales.payment_completed,
|
||||
"coins"
|
||||
);
|
||||
await updateBalances();
|
||||
} else {
|
||||
Notify($Locales.no_cash_on_you, $Locales.error, "credit-card");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getLocales() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getLocales", {});
|
||||
Locales.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
getAmountPresets();
|
||||
getLocales();
|
||||
updateBalances();
|
||||
const keyHandler = (e: KeyboardEvent) => {
|
||||
if (get(showATM) && ["Escape"].includes(e.code)) {
|
||||
fetchNui("ps-banking:client:hideUI");
|
||||
showATM.set(false);
|
||||
}
|
||||
};
|
||||
window.addEventListener("keydown", keyHandler);
|
||||
return () => window.removeEventListener("keydown", keyHandler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-screen h-screen flex items-center justify-center">
|
||||
<div
|
||||
class="absolute inset-0 flex items-center justify-center"
|
||||
in:scale={{ duration: 1000, easing: quintOut }}
|
||||
out:scale={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="h-auto w-[60%] bg-gray-800 rounded-3xl p-8 shadow-2xl relative border border-blue-200/10"
|
||||
>
|
||||
<div class="text-4xl font-bold text-center text-blue-200 mb-6">
|
||||
<i class="fa-duotone fa-atm text-blue-200 mr-2"></i>{$Locales.atm}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-6 mb-8">
|
||||
<div
|
||||
class="bg-gray-700 p-6 rounded-2xl shadow-lg flex flex-col items-center justify-center"
|
||||
>
|
||||
<div class="text-2xl font-semibold text-blue-100 mb-2">
|
||||
<i class="fa-duotone fa-money-bill-wave text-md mr-2"></i>
|
||||
{$Locales.cash}
|
||||
</div>
|
||||
<div class="text-4xl font-bold text-blue-400">
|
||||
{$currentCash.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-gray-700 p-6 rounded-2xl shadow-lg flex flex-col items-center justify-center"
|
||||
>
|
||||
<div class="text-2xl font-semibold text-blue-100 mb-2">
|
||||
<i class="fa-duotone fa-vault text-md mr-2"
|
||||
></i>{$Locales.bank_balance}
|
||||
</div>
|
||||
<div class="text-4xl font-bold text-blue-400">
|
||||
{$bankBalance.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid" style={`grid-template-columns: repeat(${$gridColsPreset}, minmax(0, 1fr)); gap: 10px;`}>
|
||||
{#each $withdrawAmounts as amount}
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-4 px-6 rounded-xl duration-500 cursor-pointer flex items-center justify-center gap-2"
|
||||
on:click={() => {
|
||||
heav(amount);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-money-bill-wave text-lg"
|
||||
></i>{$Locales.withdraw}
|
||||
{amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</button>
|
||||
{/each}
|
||||
{#each $depositAmounts as amount}
|
||||
<button
|
||||
class="bg-green-600/10 border border-green-500 hover:bg-green-800/50 text-white font-bold py-4 px-6 rounded-xl duration-500 cursor-pointer flex items-center justify-center gap-2"
|
||||
on:click={() => {
|
||||
deposit(amount);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-credit-card text-lg"></i>{$Locales.deposit}
|
||||
{amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 mt-4">
|
||||
<div class="bg-gray-700 p-4 rounded-xl shadow-lg">
|
||||
<div class="flex items-center mb-2">
|
||||
<i
|
||||
class="fa-duotone fa-money-check-edit text-xl text-green-400 mr-2"
|
||||
></i>
|
||||
<label for="Deposit" class="text-lg font-semibold text-white">
|
||||
{$Locales.deposit_amount}
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
id="Deposit"
|
||||
bind:value={$customDeposit}
|
||||
class="w-full bg-gray-800 text-white font-bold pl-4 pr-4 py-3 rounded-lg border border-green-200/10 focus:outline-none focus:border-green-400/50 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder={$Locales.deposit_amount}
|
||||
/>
|
||||
<button
|
||||
class="mt-2 w-full bg-green-600/10 border border-green-500 hover:bg-green-800/50 text-white font-bold py-2 px-4 rounded-xl duration-500 cursor-pointer flex items-center justify-center gap-2"
|
||||
on:click={() => {
|
||||
deposit(get(customDeposit));
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-piggy-bank text-lg"></i>
|
||||
{$Locales.submit}
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-gray-700 p-4 rounded-xl shadow-lg">
|
||||
<div class="flex items-center mb-2">
|
||||
<i class="fa-duotone fa-money-check-edit text-xl text-blue-400 mr-2"
|
||||
></i>
|
||||
<label for="Withdraw" class="text-lg font-semibold text-white">
|
||||
{$Locales.withdraw_amount}
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
id="Withdraw"
|
||||
bind:value={$customWithdraw}
|
||||
class="w-full bg-gray-800 font-bold text-white pl-4 pr-4 py-3 rounded-lg border border-blue-200/10 focus:outline-none focus:border-blue-400/50 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder={$Locales.withdraw_amount}
|
||||
/>
|
||||
<button
|
||||
class="mt-2 w-full bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 rounded-xl duration-500 cursor-pointer flex items-center justify-center gap-2"
|
||||
on:click={() => {
|
||||
heav(get(customWithdraw));
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-money-bill-wave text-lg"></i>
|
||||
{$Locales.submit}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute top-4 right-4 transform -translate-x-1/2 text-white">
|
||||
<button
|
||||
class="text-blue-200/50 hover:text-blue-500/50 font-bold py-2 px-4 rounded-xl duration-500 cursor-pointer flex items-center justify-center gap-2 text-gray-300 py-4 transition-all duration-500 rounded-xl hover:text-blue-300 duration-500 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
on:click={() => {
|
||||
showATM.set(false);
|
||||
fetchNui("ps-banking:client:hideUI");
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-2xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
801
resources/[tools]/ps-banking/web/src/components/Accounts.svelte
Normal file
801
resources/[tools]/ps-banking/web/src/components/Accounts.svelte
Normal file
|
@ -0,0 +1,801 @@
|
|||
<script lang="ts">
|
||||
import { writable, get, derived } from "svelte/store";
|
||||
import { slide, scale, fade } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { Notify, type Notification, Locales, Currency } from "../store/data";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { onMount } from "svelte";
|
||||
let userData = writable({});
|
||||
let accounts = writable([]);
|
||||
let totalBalance = derived(accounts, ($accounts) =>
|
||||
$accounts.reduce((acc, account) => acc + account.balance, 0)
|
||||
);
|
||||
let showModal = writable(false);
|
||||
let showRenameModal = writable(false);
|
||||
let showCreateAccountModal = writable(false);
|
||||
let showDeleteModal = writable(false);
|
||||
let showRemoveUserModal = writable(false);
|
||||
let showWithdrawModal = writable(false);
|
||||
let showDepositModal = writable(false);
|
||||
let newServerId = writable("");
|
||||
let newAccountName = writable("");
|
||||
let newAccountHolder = writable("");
|
||||
let newAccountBalance = writable(0);
|
||||
let selectedAccount = writable<number | null>(null);
|
||||
let selectedUser = writable("");
|
||||
let transactionAmount = writable<number>(0);
|
||||
|
||||
async function renameAccount(id: number) {
|
||||
const newName = get(newAccountName);
|
||||
if (newName) {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:renameAccount", {
|
||||
id,
|
||||
newName,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) =>
|
||||
accs.map((acc) =>
|
||||
acc.id === id ? { ...acc, holder: newName } : acc
|
||||
)
|
||||
);
|
||||
newAccountName.set("");
|
||||
showRenameModal.set(false);
|
||||
getAccounts();
|
||||
Notify(
|
||||
$Locales.account_renamed_successfully,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.account_rename_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Notify(
|
||||
$Locales.account_rename_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyAccountNumber(id: number) {
|
||||
const account = get(accounts).find((acc) => acc.id === id);
|
||||
if (account) {
|
||||
await fetchNui("ps-banking:client:copyAccountNumber", {
|
||||
accountNumber: account.cardNumber,
|
||||
});
|
||||
Notify($Locales.account_number_copied, $Locales.success, "clipboard");
|
||||
}
|
||||
}
|
||||
|
||||
async function addUserToAccount(accountId: number, userId: string) {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:addUserToAccount", {
|
||||
accountId,
|
||||
userId,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) => {
|
||||
const updatedAccounts = accs.map((acc) => {
|
||||
if (acc.id === accountId) {
|
||||
return {
|
||||
...acc,
|
||||
users: [
|
||||
...acc.users,
|
||||
{ name: response.userName, identifier: userId },
|
||||
],
|
||||
};
|
||||
}
|
||||
return acc;
|
||||
});
|
||||
return updatedAccounts;
|
||||
});
|
||||
Notify(
|
||||
`${response.userName} ${$Locales.user_added_successfully}`,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
showModal.set(false);
|
||||
newServerId.set("0");
|
||||
getAccounts();
|
||||
} else {
|
||||
Notify(response.message, $Locales.error, "exclamation-circle");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Notify(
|
||||
$Locales.user_addition_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeUserFromAccount() {
|
||||
const accountId = get(selectedAccount);
|
||||
const user = get(selectedUser);
|
||||
if (accountId !== null && user) {
|
||||
try {
|
||||
const response = await fetchNui(
|
||||
"ps-banking:client:removeUserFromAccount",
|
||||
{ accountId, user }
|
||||
);
|
||||
if (response.success) {
|
||||
accounts.update((accs) => {
|
||||
const updatedAccounts = accs.map((acc) =>
|
||||
acc.id === accountId
|
||||
? {
|
||||
...acc,
|
||||
users: acc.users.filter((u) => u.identifier !== user),
|
||||
}
|
||||
: acc
|
||||
);
|
||||
return updatedAccounts;
|
||||
});
|
||||
Notify(
|
||||
`${$Locales.removed_successfully}`,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
selectedUser.set("");
|
||||
showRemoveUserModal.set(false);
|
||||
getAccounts();
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.user_removal_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Notify(
|
||||
$Locales.user_removal_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.select_account_and_user,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteAccount(accountId: number) {
|
||||
const response = await fetchNui("ps-banking:client:deleteAccount", {
|
||||
accountId,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) => accs.filter((acc) => acc.id !== accountId));
|
||||
Notify(
|
||||
$Locales.account_deleted_successfully,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
showDeleteModal.set(false);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.account_deletion_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function formatCardNumber(cardNumber: string): string {
|
||||
return cardNumber.match(/.{1,4}/g)?.join(" ") || cardNumber;
|
||||
}
|
||||
|
||||
async function createNewAccount() {
|
||||
const holder = get(newAccountHolder);
|
||||
const balance = get(newAccountBalance);
|
||||
const newId = Math.max(...get(accounts).map((acc) => acc.id)) + 1;
|
||||
const rawCardNumber = Math.random().toString().slice(2, 18);
|
||||
const cardNumber = formatCardNumber(rawCardNumber);
|
||||
const newAccount = {
|
||||
id: newId,
|
||||
balance: balance,
|
||||
holder: holder,
|
||||
cardNumber: cardNumber,
|
||||
users: [],
|
||||
owner: {
|
||||
state: true,
|
||||
name: get(userData).name,
|
||||
identifier: get(userData).identifier,
|
||||
},
|
||||
};
|
||||
const response = await fetchNui("ps-banking:client:createNewAccount", {
|
||||
newAccount,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) => [...accs, newAccount]);
|
||||
newAccountHolder.set("");
|
||||
newAccountBalance.set(0);
|
||||
showCreateAccountModal.set(false);
|
||||
getAccounts();
|
||||
Notify(
|
||||
$Locales.new_account_created_successfully,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.new_account_creation_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function withdrawFromAccount() {
|
||||
const accountId = get(selectedAccount);
|
||||
const amount = get(transactionAmount);
|
||||
if (accountId !== null && amount > 0) {
|
||||
const response = await fetchNui("ps-banking:client:withdrawFromAccount", {
|
||||
accountId,
|
||||
amount,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) => {
|
||||
const updatedAccounts = accs.map((acc) =>
|
||||
acc.id === accountId && acc.balance >= amount
|
||||
? { ...acc, balance: acc.balance - amount }
|
||||
: acc
|
||||
);
|
||||
return updatedAccounts;
|
||||
});
|
||||
Notify(
|
||||
`${$Locales.withdrew} ${amount} ${$Locales.successfully}`,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
transactionAmount.set(0);
|
||||
showWithdrawModal.set(false);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.withdrawal_failed,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.select_valid_account_and_amount,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function depositToAccount() {
|
||||
const accountId = get(selectedAccount);
|
||||
const amount = get(transactionAmount);
|
||||
if (accountId !== null && amount > 0) {
|
||||
const response = await fetchNui("ps-banking:client:depositToAccount", {
|
||||
accountId,
|
||||
amount,
|
||||
});
|
||||
if (response.success) {
|
||||
accounts.update((accs) => {
|
||||
const updatedAccounts = accs.map((acc) =>
|
||||
acc.id === accountId
|
||||
? { ...acc, balance: acc.balance + amount }
|
||||
: acc
|
||||
);
|
||||
return updatedAccounts;
|
||||
});
|
||||
Notify(
|
||||
`${$Locales.deposited} ${amount} ${$Locales.successfully}`,
|
||||
$Locales.success,
|
||||
"check-circle"
|
||||
);
|
||||
transactionAmount.set(0);
|
||||
showDepositModal.set(false);
|
||||
} else {
|
||||
Notify($Locales.deposit_failed, $Locales.error, "exclamation-circle");
|
||||
}
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.select_valid_account_and_amount,
|
||||
$Locales.error,
|
||||
"exclamation-circle"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getUser() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getUser", {});
|
||||
userData.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getAccounts() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getAccounts", {});
|
||||
accounts.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
getUser();
|
||||
getAccounts();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-full h-full bg-gray-800 text-white">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px]"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="bg-gray-700/10 p-8 rounded-xl shadow-lg border border-blue-200/5"
|
||||
>
|
||||
<div class="text-5xl font-extrabold text-left text-blue-400 mb-10">
|
||||
<i class="fa-duotone fa-users text-3xl text-blue-200 mr-3"></i>
|
||||
{$Locales.accounts}
|
||||
</div>
|
||||
<div class="relative grid grid-cols-3 gap-y-10 gap-x-4 w-[90%]">
|
||||
{#each $accounts as account (account.id)}
|
||||
<div
|
||||
class="py-8 px-8 w-auto h-auto rounded-2xl shadow-lg flex flex-col justify-between bg-[#1c2333] text-blue-400 relative"
|
||||
out:fade={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-2xl font-bold">
|
||||
{account.balance.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
<div class="text-sm font-semibold">#{account.id}</div>
|
||||
</div>
|
||||
<div class="text-xl mt-2">{account.cardNumber}</div>
|
||||
<div class="flex justify-between items-center mt-4">
|
||||
<div class="text-lg">{account.owner.name} - {account.holder}</div>
|
||||
<div class="flex space-x-2">
|
||||
<button
|
||||
class="text-gray-400 hover:text-blue-300 duration-500"
|
||||
on:click={() => copyAccountNumber(account.id)}
|
||||
>
|
||||
<i class="fa-duotone fa-copy"></i>
|
||||
</button>
|
||||
{#if account.owner.identifier === get(userData).identifier || account.users.some(user => user.identifier === get(userData).identifier)}
|
||||
<button
|
||||
class="text-gray-400 hover:text-blue-300 duration-500"
|
||||
on:click={() => showRenameModal.set(account.id)}
|
||||
>
|
||||
<i class="fa-duotone fa-pen"></i>
|
||||
</button>
|
||||
{#if account.owner.identifier === get(userData).identifier}
|
||||
<button
|
||||
class="text-gray-400 hover:text-blue-300 duration-500"
|
||||
on:click={() => showModal.set(account.id)}
|
||||
>
|
||||
<i class="fa-duotone fa-user-plus"></i>
|
||||
</button>
|
||||
<button
|
||||
class="text-gray-400 hover:text-blue-300 duration-500"
|
||||
on:click={() => {
|
||||
selectedAccount.set(account.id);
|
||||
selectedUser.set("");
|
||||
showRemoveUserModal.set(true);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-user-minus"></i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="text-red-400 hover:text-red-300 duration-500"
|
||||
on:click={() => {
|
||||
selectedAccount.set(account.id);
|
||||
showDeleteModal.set(true);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-trash"></i>
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
class="text-green-400 hover:text-green-300 duration-500"
|
||||
on:click={() => {
|
||||
selectedAccount.set(account.id);
|
||||
showDepositModal.set(true);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-arrow-up"></i>
|
||||
</button>
|
||||
<button
|
||||
class="text-yellow-400 hover:text-yellow-300 duration-500"
|
||||
on:click={() => {
|
||||
selectedAccount.set(account.id);
|
||||
showWithdrawModal.set(true);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-arrow-down"></i>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<button
|
||||
class="bg-[#1c2333] mt-6 py-8 px-8 w-[250px] h-[200px] rounded-2xl shadow-lg flex items-center justify-center cursor-pointer border border-dashed border-blue-400 hover:border-blue-600 transition-all duration-500"
|
||||
on:click={() => showCreateAccountModal.set(true)}
|
||||
>
|
||||
<i class="fa-duotone fa-plus text-4xl text-gray-200"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $showModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-blue-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-exchange-alt mr-2"></i>
|
||||
{$Locales.new_user_to_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-blue-400 mb-2" for="ServerID"
|
||||
>{$Locales.server_id}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
id="ServerID"
|
||||
bind:value={$newServerId}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-blue-400 focus:outline-none focus:border-blue-600 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder="ID"
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-id-card absolute top-1/2 right-4 transform -translate-y-1/2 text-blue-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-red-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => {
|
||||
showModal.set(false);
|
||||
newServerId.set(0);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-blue-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => addUserToAccount(get(showModal), $newServerId)}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.add_user}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showRenameModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-blue-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-edit mr-2"></i>
|
||||
{$Locales.rename_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-blue-400 mb-2" for="AccountName"
|
||||
>{$Locales.new_account_name}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
id="AccountName"
|
||||
bind:value={$newAccountName}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-blue-400 focus:outline-none focus:border-blue-600 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder={$Locales.new_name}
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-pen-nib absolute top-1/2 right-4 transform -translate-y-1/2 text-blue-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-red-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => showRenameModal.set(false)}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-blue-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => renameAccount(get(showRenameModal))}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.rename}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showCreateAccountModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-blue-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-plus mr-2"></i>
|
||||
{$Locales.create_new_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-blue-400 mb-2" for="AccountHolder"
|
||||
>{$Locales.account_holder}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
id="AccountHolder"
|
||||
bind:value={$newAccountHolder}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-blue-400 focus:outline-none focus:border-blue-600 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder={$Locales.account_holder}
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-user absolute top-1/2 right-4 transform -translate-y-1/2 text-blue-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-red-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => showCreateAccountModal.set(false)}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-blue-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={createNewAccount}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.create}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showDeleteModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-red-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-exclamation-triangle mr-2"></i>
|
||||
{$Locales.delete_account}
|
||||
</h2>
|
||||
<p class="text-blue-400 mb-4">
|
||||
{$Locales.are_you_sure_you_want_to_delete_this_account}
|
||||
</p>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-gray-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => showDeleteModal.set(false)}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-red-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => deleteAccount(get(selectedAccount))}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.delete}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showRemoveUserModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-blue-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-user-minus mr-2"></i>
|
||||
{$Locales.remove_user_from_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-blue-400 mb-2" for="UserSelect"
|
||||
>{$Locales.select_user}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<select
|
||||
id="UserSelect"
|
||||
bind:value={$selectedUser}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-blue-400 focus:outline-none focus:border-blue-600 transition-colors duration-500 placeholder-gray-500 appearance-none"
|
||||
style="background-image: none; -moz-appearance: none; -webkit-appearance: none;"
|
||||
>
|
||||
{#each $accounts.find((acc) => acc.id === $selectedAccount)?.users as user}
|
||||
<option
|
||||
value={user.identifier}
|
||||
class="bg-[#283040] text-white rounded-xl font-bold pl-4 pr-12 py-4 rounded-lg transition-colors duration-500 hover:bg-blue-300/20 hover:text-gray-200 border-b border-blue-200"
|
||||
>
|
||||
{user.name}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
<i
|
||||
class="fa-duotone fa-user absolute top-1/2 right-4 transform -translate-y-1/2 text-blue-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-gray-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => {
|
||||
showRemoveUserModal.set(false);
|
||||
selectedUser.set("");
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-red-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={removeUserFromAccount}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.remove}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showWithdrawModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-yellow-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-arrow-down mr-2"></i>
|
||||
{$Locales.withdraw_from_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-yellow-400 mb-2" for="WithdrawAmount"
|
||||
>{$Locales.withdraw_amount}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
id="WithdrawAmount"
|
||||
bind:value={$transactionAmount}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-yellow-400 focus:outline-none focus:border-yellow-600 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder="0"
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-dollar-sign absolute top-1/2 right-4 transform -translate-y-1/2 text-yellow-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-gray-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => {
|
||||
showWithdrawModal.set(false);
|
||||
transactionAmount.set(0);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-yellow-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={withdrawFromAccount}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.withdraw}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $showDepositModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50"
|
||||
>
|
||||
<div
|
||||
class="bg-[#1c2333] p-8 rounded-lg shadow-2xl w-96 relative"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-green-400 mb-4 flex items-center">
|
||||
<i class="fa-duotone fa-arrow-up mr-2"></i>
|
||||
{$Locales.deposit_to_account}
|
||||
</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block text-green-400 mb-2" for="DepositAmount"
|
||||
>{$Locales.deposit_amount}</label
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
id="DepositAmount"
|
||||
bind:value={$transactionAmount}
|
||||
class="w-full bg-[#283040] text-white font-bold pl-4 pr-12 py-3 rounded-lg border border-green-400 focus:outline-none focus:border-green-600 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder="0"
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-dollar-sign absolute top-1/2 right-4 transform -translate-y-1/2 text-green-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center space-x-4">
|
||||
<button
|
||||
class="bg-gray-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => {
|
||||
showDepositModal.set(false);
|
||||
transactionAmount.set(0);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle text-lg mr-2"></i>
|
||||
{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="bg-green-600 text-white py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={depositToAccount}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle text-lg mr-2"></i>
|
||||
{$Locales.deposit}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
153
resources/[tools]/ps-banking/web/src/components/Bills.svelte
Normal file
153
resources/[tools]/ps-banking/web/src/components/Bills.svelte
Normal file
|
@ -0,0 +1,153 @@
|
|||
<script lang="ts">
|
||||
import { writable } from "svelte/store";
|
||||
import { onMount } from "svelte";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { slide, fade, scale } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { Bills } from "../store/data";
|
||||
import { Notify, Locales, Currency } from "../store/data";
|
||||
|
||||
let transactions = Bills;
|
||||
let searchQuery = writable("");
|
||||
|
||||
$: filteredTransactions = $transactions.filter(
|
||||
(transaction) =>
|
||||
transaction.description
|
||||
.toLowerCase()
|
||||
.includes($searchQuery.toLowerCase()) ||
|
||||
transaction.type.toLowerCase().includes($searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
function formatDate(dateString: string) {
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
};
|
||||
return new Date(dateString).toLocaleDateString(undefined, options);
|
||||
}
|
||||
|
||||
async function payBill(transaction: { id: any; type: any }) {
|
||||
try {
|
||||
const result = await fetchNui("ps-banking:client:payBill", {
|
||||
id: transaction.id,
|
||||
});
|
||||
if (result) {
|
||||
Notify(
|
||||
`${$Locales.pay_invoice} #${transaction.id} ${$Locales.from} ${transaction.type}`,
|
||||
$Locales.payment_completed,
|
||||
"coins"
|
||||
);
|
||||
transactions.update((items) => {
|
||||
const index = items.findIndex((t) => transaction.id === t.id);
|
||||
if (index !== -1) {
|
||||
items.splice(index, 1);
|
||||
}
|
||||
return items;
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
Notify(`${$Locales.no_money_on_account}`, `${$Locales.error}`, "coins");
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getBills", {});
|
||||
Bills.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-full h-full bg-gray-800 text-white">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px]"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="bg-gray-800/50 p-8 rounded-lg shadow-lg border border-blue-200/5"
|
||||
>
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-list text-3xl text-blue-200 mr-3"></i>
|
||||
<h2 class="text-3xl font-bold text-blue-200">{$Locales.bills}</h2>
|
||||
</div>
|
||||
<div class="bg-[#334155] rounded-full px-3 py-1 flex items-center">
|
||||
<i class="fa-duotone fa-file-invoice-dollar text-gray-400 mr-2"></i>
|
||||
<span class="text-sm text-gray-400 mr-2">{$Locales.total}</span>
|
||||
<span class="text-lg font-semibold text-white">
|
||||
{$transactions.length}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative mb-6">
|
||||
<i class="fa-duotone fa-search absolute left-4 top-4 text-gray-400"></i>
|
||||
<input
|
||||
type="text"
|
||||
class="w-full bg-gray-800 text-white pl-10 pr-4 py-3 rounded-lg border border-blue-200/10 focus:outline-none focus:border-blue-400/50 transition-colors duration-500 placeholder-gray-500"
|
||||
placeholder={$Locales.search_transactions}
|
||||
bind:value={$searchQuery}
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-6">
|
||||
{#each filteredTransactions as transaction (transaction.id)}
|
||||
<div
|
||||
class="p-4 bg-[#334155] rounded-lg flex justify-between items-center"
|
||||
out:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div class="flex flex-col space-y-1">
|
||||
<div class="flex items-center space-x-2">
|
||||
<i class="fa-duotone fa-file-invoice text-2xl text-[#f1f5f9]"
|
||||
></i>
|
||||
<span class="font-semibold text-[#f1f5f9]"
|
||||
>{transaction.description} #{transaction.id}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<i class="fa-duotone fa-user text-sm text-gray-400"></i>
|
||||
<span class="text-sm text-gray-400">{transaction.type}</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<i class="fa-duotone fa-clock text-xs text-gray-500"></i>
|
||||
<span class="text-xs text-gray-500"
|
||||
>{formatDate(transaction.date)}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex flex-col items-end space-y-1">
|
||||
<span
|
||||
class={`text-lg font-bold ${transaction.isIncome ? "text-green-500" : "text-red-500"}`}
|
||||
>
|
||||
<i class="fa-duotone fa-coins text-lg text-gray-400 mr-2"></i>
|
||||
{transaction.isIncome ? "+" : "-"}
|
||||
{transaction.amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</span>
|
||||
{#if !transaction.isPaid}
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 rounded-lg flex items-center transition-colors duration-300"
|
||||
on:click={() => {
|
||||
payBill(transaction);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-money-check-edit text-lg mr-2"></i>
|
||||
{$Locales.pay_invoice}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
113
resources/[tools]/ps-banking/web/src/components/Heav.svelte
Normal file
113
resources/[tools]/ps-banking/web/src/components/Heav.svelte
Normal file
|
@ -0,0 +1,113 @@
|
|||
<script lang="ts">
|
||||
import { writable } from "svelte/store";
|
||||
import { slide } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import {
|
||||
Notify,
|
||||
currentCash,
|
||||
bankBalance,
|
||||
Locales,
|
||||
Currency,
|
||||
} from "../store/data";
|
||||
|
||||
let withdrawAmount = writable($bankBalance);
|
||||
$: newBank = $bankBalance - $withdrawAmount;
|
||||
|
||||
async function handleWithdraw() {
|
||||
if ($bankBalance < $withdrawAmount) {
|
||||
Notify(
|
||||
`${$Locales.withdraw_error} ${$withdrawAmount.toLocaleString(
|
||||
$Currency.lang,
|
||||
{
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
}
|
||||
)}`,
|
||||
$Locales.error,
|
||||
"coins"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
`${$Locales.withdraw_success} ${$withdrawAmount.toLocaleString(
|
||||
$Currency.lang,
|
||||
{
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
}
|
||||
)}`,
|
||||
$Locales.withdraw_success,
|
||||
"coins"
|
||||
);
|
||||
await fetchNui("ps-banking:client:ATMwithdraw", {
|
||||
amount: $withdrawAmount,
|
||||
});
|
||||
currentCash.update((cash) => cash + $withdrawAmount);
|
||||
bankBalance.update((balance) => balance - $withdrawAmount);
|
||||
withdrawAmount.set(0);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<div class="absolute w-full h-full bg-gray-800 text-white">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px]"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="bg-gray-800/50 p-8 rounded-lg shadow-lg border border-blue-200/5"
|
||||
>
|
||||
<h2 class="text-3xl font-bold mb-6">{$Locales.withdraw}</h2>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.bank_balance}</label>
|
||||
<div class="flex items-center text-2xl font-semibold">
|
||||
<i class="fa-duotone fa-university text-gray-400 mr-2"></i>
|
||||
{$bankBalance.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.amount}</label>
|
||||
<div class="relative">
|
||||
<i
|
||||
class="fa-duotone fa-money-bill-wave absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
|
||||
></i>
|
||||
<input
|
||||
type="number"
|
||||
class="w-full rounded bg-gray-700/50 text-white pl-10 pr-4 py-3 border border-blue-200/10 rounded-lg focus:outline-none
|
||||
focus:border-blue-400/50 transition-colors duration-500"
|
||||
bind:value={$withdrawAmount}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.new_bank}</label>
|
||||
<div class="flex items-center text-2xl font-semibold">
|
||||
<i class="fa-duotone fa-coins text-gray-400 mr-2"></i>
|
||||
{newBank.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="w-full bg-blue-600/10 hover:bg-blue-700/10 text-white font-bold py-3 rounded transition duration-300 flex items-center justify-center border border-blue-500/50"
|
||||
on:click={handleWithdraw}
|
||||
>
|
||||
<i class="fa-duotone fa-money-check-edit text-lg mr-2"></i>
|
||||
{$Locales.withdraw_button}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
206
resources/[tools]/ps-banking/web/src/components/History.svelte
Normal file
206
resources/[tools]/ps-banking/web/src/components/History.svelte
Normal file
|
@ -0,0 +1,206 @@
|
|||
<script lang="ts">
|
||||
import { writable } from "svelte/store";
|
||||
import { onMount } from "svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { slide, fade, scale } from "svelte/transition";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import {
|
||||
showOverview,
|
||||
showBills,
|
||||
showHistory,
|
||||
notifications,
|
||||
Bills,
|
||||
Notify,
|
||||
Transactions,
|
||||
Locales,
|
||||
Currency,
|
||||
type Notification,
|
||||
} from "../store/data";
|
||||
|
||||
// Sample data
|
||||
let transactions = Transactions;
|
||||
let searchQuery = writable("");
|
||||
let showDeleteAllModal = writable(false);
|
||||
|
||||
$: filteredTransactions = $transactions.filter(
|
||||
(transaction) =>
|
||||
transaction.description
|
||||
.toLowerCase()
|
||||
.includes($searchQuery.toLowerCase()) ||
|
||||
transaction.type.toLowerCase().includes($searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
function confirmDeleteAllTransactions() {
|
||||
showDeleteAllModal.set(true);
|
||||
}
|
||||
|
||||
async function deleteAllTransactions() {
|
||||
if ($transactions.length === 0) {
|
||||
Notify($Locales.history_empty, $Locales.error, "file-invoice");
|
||||
showDeleteAllModal.set(false);
|
||||
} else {
|
||||
transactions.set([]);
|
||||
showDeleteAllModal.set(false);
|
||||
Notify($Locales.all_history_deleted, $Locales.success, "file-invoice");
|
||||
try {
|
||||
const history = await fetchNui("ps-banking:client:deleteHistory", {});
|
||||
transactions.set([]);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateString: string) {
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
};
|
||||
return new Date(dateString).toLocaleDateString(undefined, options);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
const history = await fetchNui("ps-banking:client:getHistory", {});
|
||||
transactions.set(history);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-full h-full bg-gray-800">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px] text-blue-200"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="bg-gray-800/50 p-8 rounded-lg shadow-lg border border-blue-200/5"
|
||||
>
|
||||
<div class="flex items-center mb-4">
|
||||
<i class="fa-duotone fa-list text-2xl text-blue-400 mr-3"></i>
|
||||
<h2 class="text-2xl font-bold">{$Locales.history}</h2>
|
||||
</div>
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-wallet text-xl text-gray-400 mr-2"></i>
|
||||
<span class="text-gray-400">{$Locales.total}</span>
|
||||
</div>
|
||||
<div class="absolute right-16 top-10">
|
||||
<i class="fa-duotone fa-receipt text-xl text-gray-400 mr-2"></i>
|
||||
<span class="text-xl text-white font-semibold">
|
||||
{filteredTransactions.length}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
class="bg-gray-700/50 text-blue-200 py-2 px-4 rounded-lg flex items-center hover:bg-gray-500/50 transition duration-500 border border-gray-500/20"
|
||||
on:click={confirmDeleteAllTransactions}
|
||||
>
|
||||
<i class="fa-duotone fa-trash-alt mr-2"
|
||||
></i>{$Locales.delete_all_transactions}
|
||||
</button>
|
||||
</div>
|
||||
<div class="relative mb-6">
|
||||
<i class="fa-duotone fa-search absolute left-4 top-4 text-gray-400"></i>
|
||||
<input
|
||||
type="text"
|
||||
class="w-full rounded bg-gray-700/50 text-white pl-10 pr-4 py-3 border border-blue-200/10 rounded-lg focus:outline-none
|
||||
focus:border-blue-400/50 transition-colors duration-500"
|
||||
placeholder={$Locales.search_transactions}
|
||||
bind:value={$searchQuery}
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
{#each filteredTransactions as transaction (transaction.id)}
|
||||
<div
|
||||
class="bg-[#334155] p-4 rounded-lg shadow-md transition duration-300 border border-blue-200/5"
|
||||
out:slide={{ duration: 500 }}
|
||||
>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<i
|
||||
class={`fa-duotone ${transaction.isIncome ? "fa-arrow-down-to-arc" : "fa-arrow-up-from-arc"} text-xl mr-3 ${transaction.isIncome ? "text-green-400" : "text-red-400"}`}
|
||||
></i>
|
||||
<div>
|
||||
<div class="flex items-center">
|
||||
<i
|
||||
class="fa-duotone fa-file-invoice text-lg text-gray-300 mr-2"
|
||||
></i>
|
||||
<p class="text-lg font-bold">
|
||||
{transaction.description} #{transaction.id}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<i
|
||||
class="fa-duotone fa-exchange-alt text-sm text-gray-400 mr-2"
|
||||
></i>
|
||||
<p class="text-sm text-gray-400">{transaction.type}</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-clock text-xs text-gray-500 mr-2"
|
||||
></i>
|
||||
<p class="text-xs text-gray-500">
|
||||
{formatDate(transaction.date)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-coins text-lg text-gray-400 mr-2"></i>
|
||||
<p
|
||||
class={`text-lg font-bold ${transaction.isIncome ? "text-green-500" : "text-red-500"}`}
|
||||
>
|
||||
{transaction.isIncome ? "+" : "-"}
|
||||
{transaction.amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if $showDeleteAllModal}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
||||
>
|
||||
<div
|
||||
class="bg-gray-700 p-8 rounded-lg shadow-lg w-96"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<div class="flex items-center mb-4">
|
||||
<i class="fa-duotone fa-question-circle text-3xl text-blue-400 mr-3"
|
||||
></i>
|
||||
<h2 class="text-2xl text-blue-200 font-bold">
|
||||
{$Locales.are_you_sure}
|
||||
</h2>
|
||||
</div>
|
||||
<p class="text-gray-300 mb-6">
|
||||
{$Locales.delete_confirmation}
|
||||
</p>
|
||||
<div class="flex justify-between items-center">
|
||||
<button
|
||||
class="flex items-center bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={() => showDeleteAllModal.set(false)}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle mr-2"></i>{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={deleteAllTransactions}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle mr-2"></i>{$Locales.confirm}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
115
resources/[tools]/ps-banking/web/src/components/Indseat.svelte
Normal file
115
resources/[tools]/ps-banking/web/src/components/Indseat.svelte
Normal file
|
@ -0,0 +1,115 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
import { slide } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import {
|
||||
Notify,
|
||||
currentCash,
|
||||
bankBalance,
|
||||
Locales,
|
||||
Currency,
|
||||
} from "../store/data";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
|
||||
let depositAmount = writable($currentCash);
|
||||
|
||||
$: newCash = $currentCash - $depositAmount;
|
||||
|
||||
async function handleDeposit() {
|
||||
if ($currentCash < $depositAmount) {
|
||||
Notify(
|
||||
`${$Locales.deposit_error} ${$depositAmount.toLocaleString(
|
||||
$Currency.lang,
|
||||
{
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
}
|
||||
)}`,
|
||||
$Locales.error,
|
||||
"coins"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
`${$Locales.deposit_success} ${$depositAmount.toLocaleString(
|
||||
$Currency.lang,
|
||||
{
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
}
|
||||
)} `,
|
||||
$Locales.deposit_success,
|
||||
"coins"
|
||||
);
|
||||
await fetchNui("ps-banking:client:ATMdeposit", {
|
||||
amount: $depositAmount,
|
||||
});
|
||||
currentCash.update((cash) => cash - $depositAmount);
|
||||
bankBalance.update((balance) => balance + $depositAmount);
|
||||
depositAmount.set(0);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<div class="absolute w-full h-full bg-gray-800 text-white">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px]"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div
|
||||
class="bg-gray-800/50 p-8 rounded-lg shadow-lg border border-blue-200/5"
|
||||
>
|
||||
<h2 class="text-3xl font-bold mb-6">{$Locales.deposit}</h2>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.current_cash}</label>
|
||||
<div class="flex items-center text-2xl font-semibold">
|
||||
<i class="fa-duotone fa-wallet text-gray-400 mr-2"></i>
|
||||
{$currentCash.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.amount}</label>
|
||||
<div class="relative">
|
||||
<i
|
||||
class="fa-duotone fa-money-bill-wave absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
|
||||
></i>
|
||||
<input
|
||||
type="number"
|
||||
class="w-full rounded bg-gray-700/50 text-white pl-10 pr-4 py-3 border border-blue-200/10 rounded-lg focus:outline-none
|
||||
focus:border-blue-400/50 transition-colors duration-500"
|
||||
bind:value={$depositAmount}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-12">
|
||||
<label class="block text-blue-200 mb-1">{$Locales.new_cash}</label>
|
||||
<div class="flex items-center text-2xl font-semibold">
|
||||
<i class="fa-duotone fa-coins text-gray-400 mr-2"></i>
|
||||
{newCash.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="w-full bg-blue-600/10 hover:bg-blue-700/10 text-white font-bold py-3 rounded transition duration-300 flex items-center justify-center border border-blue-500/50"
|
||||
on:click={handleDeposit}
|
||||
>
|
||||
<i class="fa-duotone fa-money-check-edit text-lg mr-2"></i>
|
||||
{$Locales.deposit_button}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
297
resources/[tools]/ps-banking/web/src/components/Main.svelte
Normal file
297
resources/[tools]/ps-banking/web/src/components/Main.svelte
Normal file
|
@ -0,0 +1,297 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { useNuiEvent } from "../utils/useNuiEvent";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { visibility } from "../store/stores";
|
||||
import OverviewPage from "./Overview.svelte";
|
||||
import BillsPage from "./Bills.svelte";
|
||||
import HistoryPage from "./History.svelte";
|
||||
import HeavPage from "./Heav.svelte";
|
||||
import IndseatPage from "./Indseat.svelte";
|
||||
import StatsPage from "./Stats.svelte";
|
||||
import AccountsPage from "./Accounts.svelte";
|
||||
import { slide, fade, scale } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import {
|
||||
showOverview,
|
||||
showBills,
|
||||
showHistory,
|
||||
showHeav,
|
||||
showIndseat,
|
||||
showStats,
|
||||
showAccounts,
|
||||
Locales,
|
||||
bankBalance,
|
||||
currentCash,
|
||||
} from "../store/data";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
async function updateBalances() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getMoneyTypes", {});
|
||||
const bank = response.find(
|
||||
(item: { name: string }) => item.name === "bank"
|
||||
);
|
||||
const cash = response.find(
|
||||
(item: { name: string }) => item.name === "cash"
|
||||
);
|
||||
if (bank) {
|
||||
bankBalance.set(bank.amount);
|
||||
}
|
||||
if (cash) {
|
||||
currentCash.set(cash.amount);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
updateBalances();
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getLocales", {});
|
||||
Locales.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="h-screen w-screen flex flex-col items-center justify-center select-none overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="absolute w-[80%] h-[90%] rounded-xl overflow-hidden"
|
||||
in:scale={{ duration: 1000, easing: quintOut }}
|
||||
out:fade={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
{#if $showOverview}
|
||||
<OverviewPage />
|
||||
{:else if $showBills}
|
||||
<BillsPage />
|
||||
{:else if $showHistory}
|
||||
<HistoryPage />
|
||||
{:else if $showHeav}
|
||||
<HeavPage />
|
||||
{:else if $showIndseat}
|
||||
<IndseatPage />
|
||||
{:else if $showStats}
|
||||
<StatsPage />
|
||||
{:else if $showAccounts}
|
||||
<AccountsPage />
|
||||
{/if}
|
||||
<!-- SideBar -->
|
||||
<div
|
||||
class="relative bg-gray-700/90 left-0 border border-gray-600/40 h-full w-28 flex flex-col items-center rounded-l-xl overflow-hidden"
|
||||
>
|
||||
<div class="relative h-full w-full top-3 left-[2px] space-y-2">
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="overview"
|
||||
class="hidden peer"
|
||||
checked={$showOverview}
|
||||
on:change={() => {
|
||||
showOverview.set(true);
|
||||
showBills.set(false);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(false);
|
||||
showStats.set(false);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-house text-3xl text-blue-300 mb-2"></i>
|
||||
<span class="relative">{$Locales.overview}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="send"
|
||||
class="hidden peer"
|
||||
checked={$showBills}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(true);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(false);
|
||||
showStats.set(false);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-file-invoice text-3xl text-blue-300 mb-2"
|
||||
></i>
|
||||
<span class="relative">{$Locales.bills}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="history"
|
||||
class="hidden peer"
|
||||
checked={$showHistory}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(true);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(false);
|
||||
showStats.set(false);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-circle-dollar text-3xl text-blue-300 mb-2"
|
||||
></i>
|
||||
<span class="relative">{$Locales.history}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="control"
|
||||
class="hidden peer"
|
||||
checked={$showHeav}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(false);
|
||||
showHeav.set(true);
|
||||
showIndseat.set(false);
|
||||
showStats.set(false);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-minus text-3xl text-blue-300 mb-2"></i>
|
||||
<span class="relative">{$Locales.withdraw}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="control"
|
||||
class="hidden peer"
|
||||
checked={$showIndseat}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(true);
|
||||
showStats.set(false);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-plus text-3xl text-blue-300 mb-2"></i>
|
||||
<span class="relative">{$Locales.deposit}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="control"
|
||||
class="hidden peer"
|
||||
checked={$showStats}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(false);
|
||||
showStats.set(true);
|
||||
showAccounts.set(false);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-chart-simple text-3xl text-blue-300 mb-2"
|
||||
></i>
|
||||
<span class="relative">{$Locales.stats}</span>
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="text-white font-bold p-0 rounded flex flex-col items-center uppercase w-[97%]"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="control"
|
||||
class="hidden peer"
|
||||
checked={$showAccounts}
|
||||
on:change={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
showIndseat.set(false);
|
||||
showStats.set(false);
|
||||
showAccounts.set(true);
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
class="w-[97%] relative flex flex-col items-center text-gray-300 py-4 peer-checked:shadow-md transition-all duration-500 rounded-xl
|
||||
peer-checked:text-blue-400 peer-checked:shadow-lg hover:text-blue-300 duration-500 peer-checked:bg-gray-600 hover:cursor-pointer hover:bg-gray-800/80"
|
||||
>
|
||||
<i class="fa-duotone fa-users text-3xl text-blue-300 mb-2"></i>
|
||||
<span class="relative">{$Locales.accounts}</span>
|
||||
</span>
|
||||
</label>
|
||||
<!-- Close -->
|
||||
<div class="relative -bottom-48 left-[.5px]">
|
||||
<button
|
||||
class="w-[95%] text-blue-200 font-bold uppercase p-5 rounded-lg hover:bg-gray-800/80 duration-500 h-[100px] flex flex-col items-center"
|
||||
on:click={() => {
|
||||
fetchNui("ps-banking:client:hideUI");
|
||||
visibility.set(false);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-circle-xmark text-3xl text-blue-300 mb-2"
|
||||
></i>
|
||||
<span class="relative">{$Locales.close}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
755
resources/[tools]/ps-banking/web/src/components/Overview.svelte
Normal file
755
resources/[tools]/ps-banking/web/src/components/Overview.svelte
Normal file
|
@ -0,0 +1,755 @@
|
|||
<script lang="ts">
|
||||
import { writable } from "svelte/store";
|
||||
import { onMount } from "svelte";
|
||||
import Chart from "chart.js/auto";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { slide, fade, scale } from "svelte/transition";
|
||||
import {
|
||||
showOverview,
|
||||
showBills,
|
||||
showHistory,
|
||||
showHeav,
|
||||
notifications,
|
||||
Bills,
|
||||
Notify,
|
||||
Transactions,
|
||||
currentCash,
|
||||
bankBalance,
|
||||
Locales,
|
||||
Currency,
|
||||
type Notification,
|
||||
} from "../store/data";
|
||||
|
||||
let notificationId = 0;
|
||||
let transactions = Bills;
|
||||
let phone = false;
|
||||
let showSureModalBills = writable(false);
|
||||
let showTransferModal = writable(false);
|
||||
let transferData = writable({
|
||||
idOrPhone: "",
|
||||
amount: 0,
|
||||
confirm: false,
|
||||
contactType: "none",
|
||||
});
|
||||
|
||||
let weeklyData = writable({
|
||||
totalReceived: 0,
|
||||
totalUsed: 0,
|
||||
});
|
||||
|
||||
let chart: Chart;
|
||||
let chartCanvas: HTMLCanvasElement;
|
||||
|
||||
async function fetchWeeklySummary() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getWeeklySummary", {});
|
||||
if (response) {
|
||||
weeklyData.set(response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateBalances() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getMoneyTypes", {});
|
||||
const bank = response.find(
|
||||
(item: { name: string }) => item.name === "bank"
|
||||
);
|
||||
const cash = response.find(
|
||||
(item: { name: string }) => item.name === "cash"
|
||||
);
|
||||
if (bank) {
|
||||
bankBalance.set(bank.amount);
|
||||
}
|
||||
if (cash) {
|
||||
currentCash.set(cash.amount);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function payAllBills() {
|
||||
const success = await fetchNui("ps-banking:client:payAllBills", {});
|
||||
if (success) {
|
||||
await getBills();
|
||||
Notify(
|
||||
$Locales.pay_all_bills_success,
|
||||
$Locales.payment_completed,
|
||||
"money-bill"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.pay_all_bills_error,
|
||||
$Locales.error,
|
||||
"circle-exclamation"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
showTransferModal.set(true);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
showTransferModal.set(false);
|
||||
transferData.set({
|
||||
idOrPhone: "",
|
||||
amount: 0,
|
||||
confirm: false,
|
||||
contactType: "none",
|
||||
});
|
||||
}
|
||||
|
||||
async function getBills() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:getBills", {});
|
||||
Bills.set(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getHistory() {
|
||||
try {
|
||||
const history = await fetchNui("ps-banking:client:getHistory", {});
|
||||
Transactions.set(history);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmTransfer(id: any, amount: any, method: any) {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:transferMoney", {
|
||||
id: id,
|
||||
amount: amount,
|
||||
method: method,
|
||||
});
|
||||
if (response.success) {
|
||||
Notify(response.message, $Locales.payment_completed, "user");
|
||||
} else {
|
||||
Notify(response.message, $Locales.error, "user");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
transferData.update((data) => {
|
||||
data.confirm = true;
|
||||
return data;
|
||||
});
|
||||
showTransferModal.set(false);
|
||||
transferData.set({
|
||||
idOrPhone: "",
|
||||
amount: 0,
|
||||
confirm: false,
|
||||
contactType: "none",
|
||||
});
|
||||
}
|
||||
|
||||
let bankData = {
|
||||
balance: $bankBalance,
|
||||
cash: $currentCash,
|
||||
transactions: $Transactions,
|
||||
};
|
||||
|
||||
$: bankData = {
|
||||
balance: $bankBalance,
|
||||
cash: $currentCash,
|
||||
transactions: $Transactions,
|
||||
};
|
||||
|
||||
async function heav() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:ATMwithdraw", {
|
||||
amount: $bankBalance,
|
||||
});
|
||||
if (response) {
|
||||
updateStuff();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deposit() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:ATMdeposit", {
|
||||
amount: $currentCash,
|
||||
});
|
||||
if (response) {
|
||||
updateStuff();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function createChart() {
|
||||
if (chartCanvas) {
|
||||
chart = new Chart(chartCanvas, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: [$Locales.income, $Locales.expenses],
|
||||
datasets: [
|
||||
{
|
||||
label: $Locales.weekly_summary,
|
||||
data: [0, 0],
|
||||
backgroundColor: ["#3b82f6", "#ef4444"],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
weeklyData.subscribe((data) => {
|
||||
if (chart) {
|
||||
chart.data.datasets[0].data = [data.totalReceived, data.totalUsed];
|
||||
chart.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function updateStuff() {
|
||||
// Hot update
|
||||
await getBills();
|
||||
await getHistory();
|
||||
await fetchWeeklySummary();
|
||||
await updateBalances();
|
||||
}
|
||||
|
||||
async function phoneOption() {
|
||||
try {
|
||||
const response = await fetchNui("ps-banking:client:phoneOption", {});
|
||||
phone = response
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
createChart();
|
||||
updateStuff();
|
||||
updateStuff();
|
||||
phoneOption();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute w-full h-full bg-gray-800">
|
||||
<div
|
||||
class="absolute top-0 left-[240px] w-screen h-screen overflow-hidden p-6 text-white"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<!-- Quick Actions -->
|
||||
<div class="mb-8">
|
||||
<div class="text-xl mb-4 text-blue-200">{$Locales.total_balance}</div>
|
||||
<div class="text-3xl font-bold mb-8 text-blue-300">
|
||||
{$bankBalance.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-2xl mb-4 text-blue-200">{$Locales.quick_actions}</div>
|
||||
<div class="flex space-x-4">
|
||||
<div
|
||||
class="flex flex-col items-center bg-gray-700 rounded-xl p-4 w-[280px]"
|
||||
>
|
||||
<i
|
||||
class="fa-duotone fa-arrow-right-arrow-left text-4xl mb-2 text-blue-400"
|
||||
></i>
|
||||
<div class="text-2xl font-bold mb-2 text-blue-200">
|
||||
{$Locales.transfer_money}
|
||||
</div>
|
||||
<div class="text-sm mb-2 text-gray-400">
|
||||
{$Locales.easy_transfer}
|
||||
</div>
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 mt-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={openModal}
|
||||
>
|
||||
{$Locales.transfer}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col items-center bg-gray-700 rounded-xl p-4 w-[280px]"
|
||||
>
|
||||
<i
|
||||
class="fa-duotone fa-file-invoice-dollar text-4xl mb-2 text-blue-400"
|
||||
></i>
|
||||
<div class="text-2xl font-bold mb-2 text-blue-200">
|
||||
{$Locales.pay_bills}
|
||||
</div>
|
||||
<div class="text-sm mb-2 text-gray-400">
|
||||
{$Locales.pay_pending_bills}
|
||||
</div>
|
||||
<button
|
||||
class="relative -bottom-auto bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-8 mt-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={() => {
|
||||
showSureModalBills.set(true);
|
||||
}}
|
||||
>
|
||||
{$Locales.pay}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col items-center bg-gray-700 rounded-xl p-4 w-[280px]"
|
||||
>
|
||||
<i class="fa-duotone fa-credit-card text-4xl mb-2 text-blue-400"></i>
|
||||
<div class="text-2xl font-bold mb-2 text-blue-200">
|
||||
{$Locales.withdraw_all_money}
|
||||
</div>
|
||||
<div class="text-sm mb-2 text-gray-400">
|
||||
{$Locales.withdraw_all_from_account}
|
||||
</div>
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 mt-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={() => {
|
||||
if ($bankBalance <= 0) {
|
||||
Notify(
|
||||
$Locales.no_money_on_account,
|
||||
$Locales.error,
|
||||
"credit-card"
|
||||
);
|
||||
} else {
|
||||
Notify(
|
||||
$Locales.withdraw_all_success,
|
||||
$Locales.success,
|
||||
"credit-card"
|
||||
);
|
||||
setTimeout(() => {
|
||||
heav();
|
||||
}, 200);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{$Locales.withdraw}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col items-center bg-gray-700 rounded-xl p-4 w-[280px]"
|
||||
>
|
||||
<i class="fa-duotone fa-piggy-bank text-4xl mb-2 text-blue-400"></i>
|
||||
<div class="text-2xl font-bold mb-2 text-blue-200">
|
||||
{$Locales.deposit_cash}
|
||||
</div>
|
||||
<div class="text-sm mb-2 text-gray-400">
|
||||
{$Locales.deposit_all_cash}
|
||||
</div>
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 mt-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={() => {
|
||||
if ($currentCash <= 0) {
|
||||
Notify($Locales.no_cash_on_you, $Locales.error, "coins");
|
||||
} else {
|
||||
Notify($Locales.deposit_all_success, $Locales.success, "coins");
|
||||
setTimeout(() => {
|
||||
deposit();
|
||||
}, 200);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{$Locales.deposit}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lower Section -->
|
||||
<div class="flex space-x-4 mt-4">
|
||||
<!-- Weekly Summary -->
|
||||
<div class="bg-gray-700 rounded-xl p-6 w-[380px] h-[400px] flex-none">
|
||||
<div class="flex items-center mb-4">
|
||||
<i class="fa-duotone fa-calendar-week text-2xl text-blue-400 mr-2"
|
||||
></i>
|
||||
<span class="text-blue-200 font-bold text-xl"
|
||||
>{$Locales.weekly_summary}</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="space-y-4 border border-dashed border-blue-400 rounded-lg p-4"
|
||||
>
|
||||
<div class="flex justify-between border-b border-gray-600 pb-2">
|
||||
<span>{$Locales.income}</span>
|
||||
<span class="text-blue-400">
|
||||
{#if $weeklyData.totalReceived !== undefined}
|
||||
{$weeklyData.totalReceived.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
{:else}
|
||||
0
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between border-b border-gray-600 pb-2">
|
||||
<span>{$Locales.expenses}</span>
|
||||
<span class="text-red-400">
|
||||
{#if $weeklyData.totalUsed !== undefined}
|
||||
{$weeklyData.totalUsed.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
{:else}
|
||||
0
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<div class="flex items-center mb-2">
|
||||
<i class="fa-duotone fa-chart-bar text-xl text-blue-400 mr-2"></i>
|
||||
<span>{$Locales.report}</span>
|
||||
</div>
|
||||
<div>
|
||||
<canvas bind:this={chartCanvas}></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latest Transactions -->
|
||||
<div class="bg-gray-700 rounded-xl p-6 w-[380px] h-[400px] flex-none">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-file-invoice text-2xl text-blue-400 mr-2"
|
||||
></i>
|
||||
<span class="text-blue-200 font-bold text-xl"
|
||||
>{$Locales.latest_transactions}</span
|
||||
>
|
||||
</div>
|
||||
<div class="bg-gray-600 rounded-full px-2 py-1">
|
||||
<span class="text-white text-sm"
|
||||
>{bankData.transactions.length}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="space-y-3 border border-dashed border-blue-400 rounded-lg p-4 h-[310px]"
|
||||
>
|
||||
{#if bankData.transactions.length > 0}
|
||||
{#each bankData.transactions.slice(0, 5) as transaction}
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="truncate">{transaction.description}</span>
|
||||
<p
|
||||
class={`text-md font-bold ${transaction.isIncome ? "text-green-500" : "text-red-500"}`}
|
||||
>
|
||||
{transaction.isIncome ? "+" : "-"}
|
||||
{transaction.amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
<div class="border-b border-gray-600"></div>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="mt-6 flex justify-center">
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 mt-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(false);
|
||||
showHistory.set(true);
|
||||
showHeav.set(false);
|
||||
}}
|
||||
>
|
||||
{$Locales.see_all}
|
||||
</button>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="p-4 text-center text-blue-200">
|
||||
<i class="fa-duotone fa-check-circle text-2xl mb-2"></i>
|
||||
<p>{$Locales.no_transactions}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-700 rounded-xl p-4 w-[380px] h-[400px] flex-none">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-file-exclamation text-xl text-blue-400 mr-2"
|
||||
></i>
|
||||
<span class="text-blue-200 font-bold text-lg"
|
||||
>{$Locales.unpaid_bills}</span
|
||||
>
|
||||
</div>
|
||||
<div class="bg-gray-600 rounded-full px-2 py-1">
|
||||
<span class="text-white text-sm">{$transactions.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="space-y-0 border border-dashed border-blue-400 p-1 rounded-lg overflow-auto mt-6 h-[310px]"
|
||||
>
|
||||
{#if $transactions.length > 0}
|
||||
{#each $transactions.slice(0, 2) as transaction (transaction.id)}
|
||||
{#if !transaction.isPaid}
|
||||
<div class="p-2 rounded-lg flex justify-between items-center">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center">
|
||||
<span class="font-semibold text-[#f1f5f9]"
|
||||
>{transaction.description} #{transaction.id}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center mt-1">
|
||||
<span class="text-sm text-gray-400"
|
||||
>{transaction.type}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center mt-1">
|
||||
<span class="text-xs text-gray-500"
|
||||
>{transaction.timeAgo}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex flex-col items-end">
|
||||
<span
|
||||
class={`text-lg ${transaction.isIncome ? "text-green-400" : "text-red-400"}`}
|
||||
>
|
||||
{transaction.isIncome ? "+" : "-"}
|
||||
{transaction.amount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
</span>
|
||||
<div class="flex items-center mt-0">
|
||||
<div class="text-sm text-gray-400">
|
||||
{transaction.date}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-b border-gray-600"></div>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="mb-4 space-y-2 text-center">
|
||||
<div class="mt-[70px] flex justify-center">
|
||||
<button
|
||||
class="bg-blue-600/10 border border-blue-500 hover:bg-blue-800/50 text-white font-bold py-2 px-4 duration-500 rounded-lg cursor-pointer"
|
||||
on:click={() => {
|
||||
showOverview.set(false);
|
||||
showBills.set(true);
|
||||
showHistory.set(false);
|
||||
showHeav.set(false);
|
||||
}}
|
||||
>
|
||||
{$Locales.see_all}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="p-4 text-center text-blue-200">
|
||||
<i class="fa-duotone fa-check-circle text-2xl mb-2"></i>
|
||||
<p>{$Locales.no_unpaid_bills}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- MODALS -->
|
||||
{#if $showTransferModal}
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
||||
>
|
||||
<div
|
||||
class="p-8 bg-gray-800 rounded-lg shadow-lg w-96"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<div class="flex items-center mb-4">
|
||||
<i
|
||||
class="fa-duotone fa-arrow-right-arrow-left text-3xl text-blue-400 mr-3"
|
||||
></i>
|
||||
<h2 class="text-2xl text-blue-200 font-bold">
|
||||
{$Locales.transfer_money}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- Payment Method Selection -->
|
||||
<div class="mb-6">
|
||||
<p class="capitalize font-semibold text-blue-200 mb-2">
|
||||
{$Locales.payment_method}
|
||||
</p>
|
||||
<div class="flex flex-col space-y-4">
|
||||
{#if phone}
|
||||
<label
|
||||
class="flex items-center cursor-pointer bg-gray-700/50 rounded-lg p-3 border border-gray-600/20 hover:border-blue-400 transition duration-300"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="payment"
|
||||
value="phone"
|
||||
bind:group={$transferData.contactType}
|
||||
class="hidden peer"
|
||||
/>
|
||||
<i class="fa-duotone fa-phone text-lg text-blue-400 mr-3"></i>
|
||||
<span class="text-white font-bold">{$Locales.phone_number}</span
|
||||
>
|
||||
<div class="ml-auto hidden peer-checked:block">
|
||||
<i class="fa-duotone fa-check-circle text-blue-400"></i>
|
||||
</div>
|
||||
</label>
|
||||
{/if}
|
||||
<label
|
||||
class="flex items-center cursor-pointer bg-gray-700/50 rounded-lg p-3 border border-gray-600/20 hover:border-blue-400 transition duration-300"
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="payment"
|
||||
value="id"
|
||||
bind:group={$transferData.contactType}
|
||||
class="hidden peer"
|
||||
/>
|
||||
<i class="fa-duotone fa-id-badge text-lg text-blue-400 mr-3"></i>
|
||||
<span class="text-white font-bold">{$Locales.id}</span>
|
||||
<div class="ml-auto hidden peer-checked:block">
|
||||
<i class="fa-duotone fa-check-circle text-blue-400"></i>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ID or Phone Number Input -->
|
||||
{#if $transferData.contactType === "phone" || $transferData.contactType === "id"}
|
||||
<div class="mb-6">
|
||||
<label class="block text-gray-400 mb-2">
|
||||
<i class="fa-duotone fa-id-card text-blue-400 mr-2"></i>
|
||||
{#if phone}
|
||||
{$Locales.id_or_phone_number}
|
||||
{:else}
|
||||
{$Locales.id}
|
||||
{/if}
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
class="w-full p-3 bg-gray-700/50 text-white pr-10 border border-blue-200/10 rounded-lg focus:outline-none
|
||||
focus:border-blue-400/50 transition-colors duration-500"
|
||||
bind:value={$transferData.idOrPhone}
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-user absolute top-1/2 right-3 transform -translate-y-1/2 text-gray-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Amount Input -->
|
||||
<div class="mb-6">
|
||||
<label class="block text-gray-400 mb-2">
|
||||
<i class="fa-duotone fa-money-bill-wave text-blue-400 mr-2"
|
||||
></i>{$Locales.amount}
|
||||
</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
class="w-full p-3 bg-gray-700/50 text-white pr-10 border border-blue-200/10 rounded-lg focus:outline-none
|
||||
focus:border-blue-400/50 transition-colors duration-500"
|
||||
bind:value={$transferData.amount}
|
||||
/>
|
||||
<i
|
||||
class="fa-duotone fa-dollar-sign absolute top-1/2 right-3 transform -translate-y-1/2 text-gray-400"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex justify-between items-center mt-6">
|
||||
<button
|
||||
class="flex items-center bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={closeModal}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle mr-2"></i>{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={async () => {
|
||||
confirmTransfer(
|
||||
$transferData.idOrPhone,
|
||||
$transferData.amount,
|
||||
$transferData.contactType
|
||||
);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle mr-2"></i>{$Locales.confirm}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $showSureModalBills}
|
||||
<div
|
||||
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
||||
>
|
||||
<div
|
||||
class="bg-gray-700 p-8 rounded-lg shadow-lg w-96"
|
||||
in:scale={{ duration: 250, easing: quintOut }}
|
||||
out:scale={{ duration: 250, easing: quintOut }}
|
||||
>
|
||||
<div class="flex items-center mb-4">
|
||||
<i class="fa-duotone fa-question-circle text-3xl text-blue-400 mr-3"
|
||||
></i>
|
||||
<h2 class="text-2xl text-blue-200 font-bold">
|
||||
{$Locales.are_you_sure}
|
||||
</h2>
|
||||
</div>
|
||||
<p class="text-gray-300 mb-6">
|
||||
{$Locales.confirm_pay_all_bills}
|
||||
</p>
|
||||
<div class="flex justify-between items-center">
|
||||
<button
|
||||
class="flex items-center bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={() => {
|
||||
showSureModalBills.set(false);
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-times-circle mr-2"></i>{$Locales.cancel}
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded focus:outline-none"
|
||||
on:click={async () => {
|
||||
if ($transactions.length > 0) {
|
||||
await payAllBills();
|
||||
showSureModalBills.set(false);
|
||||
} else {
|
||||
showSureModalBills.set(false);
|
||||
Notify(
|
||||
$Locales.pay_all_bills_error,
|
||||
$Locales.error,
|
||||
"circle-exclamation"
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i class="fa-duotone fa-check-circle mr-2"></i>{$Locales.confirm}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
228
resources/[tools]/ps-banking/web/src/components/Stats.svelte
Normal file
228
resources/[tools]/ps-banking/web/src/components/Stats.svelte
Normal file
|
@ -0,0 +1,228 @@
|
|||
<script lang="ts">
|
||||
import { writable } from "svelte/store";
|
||||
import { slide, scale } from "svelte/transition";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { onMount } from "svelte";
|
||||
import {
|
||||
Notify,
|
||||
currentCash,
|
||||
bankBalance,
|
||||
Locales,
|
||||
Currency,
|
||||
} from "../store/data";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import {
|
||||
Chart,
|
||||
LineController,
|
||||
LineElement,
|
||||
PointElement,
|
||||
LinearScale,
|
||||
Title,
|
||||
CategoryScale,
|
||||
Tooltip,
|
||||
} from "chart.js";
|
||||
|
||||
let totalTransactions = writable(0);
|
||||
let totalAmount = writable(0);
|
||||
|
||||
let dataSheets = {
|
||||
Transactions: [],
|
||||
Dates: [],
|
||||
};
|
||||
|
||||
let chart: Chart<"line", never[], string>;
|
||||
|
||||
async function fetchTransactionStats() {
|
||||
try {
|
||||
const stats = await fetchNui("ps-banking:client:getTransactionStats", {});
|
||||
totalTransactions.set(stats.totalCount);
|
||||
totalAmount.set(stats.totalAmount);
|
||||
|
||||
const transactionData = stats.transactionData.map(
|
||||
(stat: { amount: any }) => stat.amount
|
||||
);
|
||||
const transactionDates = stats.transactionData.map(
|
||||
(stat: { date: any }) => new Date(stat.date).toLocaleDateString()
|
||||
);
|
||||
|
||||
dataSheets.Transactions = transactionData;
|
||||
dataSheets.Dates = transactionDates;
|
||||
|
||||
if (chart) {
|
||||
chart.data.labels = transactionDates;
|
||||
chart.data.datasets[0].data = transactionData;
|
||||
chart.update();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching transaction stats:", error);
|
||||
}
|
||||
}
|
||||
|
||||
Chart.register(
|
||||
LineController,
|
||||
LineElement,
|
||||
PointElement,
|
||||
LinearScale,
|
||||
Title,
|
||||
CategoryScale,
|
||||
Tooltip
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
fetchTransactionStats();
|
||||
|
||||
// @ts-expect-error
|
||||
const ctx = document.getElementById("transactionChart").getContext("2d");
|
||||
chart = new Chart(ctx, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: dataSheets.Dates,
|
||||
datasets: [
|
||||
{
|
||||
label: "Transactions",
|
||||
data: dataSheets.Transactions,
|
||||
borderColor: "rgba(59, 130, 246, 1)",
|
||||
backgroundColor: "rgba(59, 130, 246, 0.2)",
|
||||
fill: true,
|
||||
tension: 0.5,
|
||||
pointStyle: "rectRounded",
|
||||
pointRadius: 5,
|
||||
pointHoverRadius: 7,
|
||||
borderWidth: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: "top",
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
color: "white",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: "rgba(0,0,0,0.7)",
|
||||
titleColor: "white",
|
||||
bodyColor: "white",
|
||||
cornerRadius: 4,
|
||||
displayColors: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: $Locales.date,
|
||||
color: "white",
|
||||
},
|
||||
ticks: {
|
||||
color: "white",
|
||||
},
|
||||
grid: {
|
||||
color: "rgba(255,255,255,0.1)",
|
||||
},
|
||||
},
|
||||
y: {
|
||||
display: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: $Locales.amount,
|
||||
color: "white",
|
||||
},
|
||||
ticks: {
|
||||
color: "white",
|
||||
},
|
||||
grid: {
|
||||
color: "rgba(255,255,255,0.1)",
|
||||
},
|
||||
suggestedMin: 0,
|
||||
suggestedMax: dataSheets.Transactions.reduce(
|
||||
(acc, val) => acc + val,
|
||||
0
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<div class="absolute w-full h-full bg-gray-800 text-white">
|
||||
<div
|
||||
class="absolute w-[90%] h-full p-6 overflow-auto left-[130px]"
|
||||
in:slide={{ duration: 1000, easing: quintOut }}
|
||||
>
|
||||
<div class="bg-gray-700/20 rounded-lg shadow-md p-6">
|
||||
<h2 class="text-3xl font-bold mb-6">{$Locales.statistics_reports}</h2>
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-duotone fa-chart-line text-3xl text-blue-200 mr-3"></i>
|
||||
<h3 class="text-2xl font-semibold text-blue-200">
|
||||
{$Locales.overview}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="bg-gray-500/40 rounded-xl px-3 py-1 flex items-center">
|
||||
<i class="fa-duotone fa-wallet text-gray-400 mr-2"></i>
|
||||
<span class="text-lg font-semibold text-white">
|
||||
{$Locales.total_balance}: {#if $bankBalance !== undefined}
|
||||
{$bankBalance.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<div class="bg-gray-700 p-4 rounded-lg shadow">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h4 class="text-xl font-semibold text-blue-200">
|
||||
{$Locales.total_transactions}
|
||||
</h4>
|
||||
<i class="fa-duotone fa-exchange-alt text-yellow-400 text-2xl"></i>
|
||||
</div>
|
||||
<p class="text-2xl font-bold">{$totalTransactions}</p>
|
||||
</div>
|
||||
<div class="bg-gray-700 p-4 rounded-lg shadow">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h4 class="text-xl font-semibold text-blue-200">
|
||||
{$Locales.amount}
|
||||
</h4>
|
||||
<i class="fa-duotone fa-coins text-green-400 text-2xl"></i>
|
||||
</div>
|
||||
<p class="text-2xl font-bold">
|
||||
{#if $totalAmount !== undefined}
|
||||
{$totalAmount.toLocaleString($Currency.lang, {
|
||||
style: "currency",
|
||||
currency: $Currency.currency,
|
||||
minimumFractionDigits: 0,
|
||||
})}
|
||||
{:else}
|
||||
0
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-700 p-4 rounded-lg shadow">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h4 class="text-xl font-semibold text-blue-200">
|
||||
{$Locales.transactions_trend}
|
||||
</h4>
|
||||
<i class="fa-duotone fa-chart-line text-blue-400 text-2xl"></i>
|
||||
</div>
|
||||
<div
|
||||
class="relative w-[1000px] left-[15%]"
|
||||
in:scale={{ duration: 2500, easing: quintOut }}
|
||||
>
|
||||
<canvas id="transactionChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
3
resources/[tools]/ps-banking/web/src/global.d.ts
vendored
Normal file
3
resources/[tools]/ps-banking/web/src/global.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
declare module '*.csv';
|
8
resources/[tools]/ps-banking/web/src/main.ts
Normal file
8
resources/[tools]/ps-banking/web/src/main.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import "./app.pcss";
|
||||
import App from "./App.svelte";
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById("app")!,
|
||||
});
|
||||
|
||||
export default app;
|
|
@ -0,0 +1,46 @@
|
|||
<script lang="ts">
|
||||
import { useNuiEvent } from "../utils/useNuiEvent";
|
||||
import { fetchNui } from "../utils/fetchNui";
|
||||
import { onMount } from "svelte";
|
||||
import { visibility } from "../store/stores";
|
||||
import ATM from "../components/ATM.svelte";
|
||||
import { showATM } from "../store/data";
|
||||
|
||||
let isVisible: boolean;
|
||||
|
||||
useNuiEvent<boolean>("openATM", () => {
|
||||
showATM.set(true);
|
||||
});
|
||||
|
||||
visibility.subscribe((visible) => {
|
||||
isVisible = visible;
|
||||
});
|
||||
|
||||
useNuiEvent<boolean>("openBank", () => {
|
||||
visibility.set(true);
|
||||
});
|
||||
useNuiEvent<boolean>("hideGarageMenu", () => {
|
||||
visibility.set(false);
|
||||
});
|
||||
onMount(() => {
|
||||
const keyHandler = (e: KeyboardEvent) => {
|
||||
if (isVisible && ["Escape"].includes(e.code)) {
|
||||
fetchNui("ps-banking:client:hideUI");
|
||||
visibility.set(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", keyHandler);
|
||||
|
||||
return () => window.removeEventListener("keydown", keyHandler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<main>
|
||||
{#if isVisible}
|
||||
<slot />
|
||||
{/if}
|
||||
{#if $showATM}
|
||||
<ATM />
|
||||
{/if}
|
||||
</main>
|
250
resources/[tools]/ps-banking/web/src/store/data.ts
Normal file
250
resources/[tools]/ps-banking/web/src/store/data.ts
Normal file
|
@ -0,0 +1,250 @@
|
|||
import { writable, type Writable } from "svelte/store";
|
||||
|
||||
export interface Notification {
|
||||
id: number;
|
||||
message: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export const notifications = writable<Notification[]>([]);
|
||||
let notificationId = 0;
|
||||
|
||||
export function Notify(message: string, title: string, icon: string) {
|
||||
notificationId += 1;
|
||||
const newNotification: Notification = {
|
||||
id: notificationId,
|
||||
message,
|
||||
title,
|
||||
icon,
|
||||
};
|
||||
notifications.update((n) => [...n, newNotification]);
|
||||
setTimeout(() => {
|
||||
notifications.update((n) =>
|
||||
n.filter((notification) => notification.id !== newNotification.id)
|
||||
);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
export const showOverview = writable(true);
|
||||
export const showBills = writable(false);
|
||||
export const showHistory = writable(false);
|
||||
export const showHeav = writable(false);
|
||||
export const showIndseat = writable(false);
|
||||
export const showStats = writable(false);
|
||||
export const showAccounts = writable(false);
|
||||
export const showATM = writable(false);
|
||||
export const currentCash = writable(500);
|
||||
export const bankBalance = writable(10000);
|
||||
|
||||
export const Currency = writable({
|
||||
lang: "en", // da-DK
|
||||
currency: "USD", // DKK
|
||||
});
|
||||
|
||||
export const Locales = writable({
|
||||
atm: "ATM",
|
||||
cash: "Cash",
|
||||
bank_balance: "Bank Balance",
|
||||
deposit_amount: "Deposit Amount",
|
||||
withdraw_amount: "Withdraw Amount",
|
||||
submit: "Submit",
|
||||
close: "Close",
|
||||
overview: "Overview",
|
||||
bills: "Bills",
|
||||
history: "History",
|
||||
withdraw: "Withdraw",
|
||||
deposit: "Deposit",
|
||||
stats: "Stats",
|
||||
transactions: "Transactions",
|
||||
total: "Total",
|
||||
search_transactions: "Search transactions...",
|
||||
description: "Description",
|
||||
type: "Type",
|
||||
time_ago: "Time Ago",
|
||||
amount: "Amount",
|
||||
date: "Date",
|
||||
pay_invoice: "Pay Invoice",
|
||||
payment_completed: "Payment Completed",
|
||||
from: "From",
|
||||
delete_all_transactions: "Delete All Transactions",
|
||||
are_you_sure: "Are you sure?",
|
||||
delete_confirmation:
|
||||
"Are you sure you want to delete all your transactions? (Only do this if the menu lags!)",
|
||||
cancel: "Cancel",
|
||||
confirm: "Confirm",
|
||||
history_empty: "Your history is empty",
|
||||
all_history_deleted: "You have deleted all your history",
|
||||
error: "Error",
|
||||
success: "Success",
|
||||
new_cash: "New Cash",
|
||||
withdraw_success: "Withdrawal Successful",
|
||||
withdraw_error: "Your bank account does not have enough funds",
|
||||
withdraw_button: "WITHDRAW",
|
||||
new_bank: "New Bank Balance",
|
||||
current_cash: "Current Cash",
|
||||
deposit_success: "Deposit Successful",
|
||||
deposit_error: "You do not have enough cash",
|
||||
deposit_button: "DEPOSIT",
|
||||
total_balance: "Total Balance",
|
||||
quick_actions: "Quick Actions",
|
||||
transfer_money: "Transfer Money",
|
||||
easy_transfer: "Easily transfer money to people",
|
||||
transfer: "Transfer",
|
||||
pay_bills: "Pay Bills",
|
||||
pay_pending_bills: "Quickly pay your pending bills",
|
||||
pay: "Pay",
|
||||
withdraw_all_money: "Withdraw All Money",
|
||||
withdraw_all_from_account: "Withdraw all your money from your account",
|
||||
deposit_cash: "Deposit Cash",
|
||||
deposit_all_cash: "Deposit all your cash into your account",
|
||||
weekly_summary: "Weekly Summary",
|
||||
income: "Income",
|
||||
expenses: "Expenses",
|
||||
report: "Report",
|
||||
latest_transactions: "Latest Transactions",
|
||||
see_all: "SEE ALL",
|
||||
unpaid_bills: "Unpaid Invoices",
|
||||
no_unpaid_bills: "No unpaid invoices",
|
||||
confirm_pay_all_bills: "Are you sure you want to pay all your bills?",
|
||||
pay_all_bills: "Pay All Bills",
|
||||
pay_all_bills_success: "You have paid all your bills!",
|
||||
pay_all_bills_error: "You have no bills",
|
||||
payment_method: "Payment Method",
|
||||
phone_number: "Phone Number",
|
||||
id: "ID",
|
||||
id_or_phone_number: "ID or Phone Number",
|
||||
no_cash_on_you: "You have no cash on you",
|
||||
deposit_all_success: "All your cash has been deposited",
|
||||
no_money_on_account: "Your account is empty",
|
||||
withdraw_all_success: "You have withdrawn all your money from the account",
|
||||
invoices: "Invoices",
|
||||
statistics_reports: "Statistics and Reports",
|
||||
balance_trend: "Balance Trend",
|
||||
balance: "Balance",
|
||||
used: "Used",
|
||||
month: "Month",
|
||||
balance_dkk: "Balance",
|
||||
withdrawn: "You have withdrawn",
|
||||
deposited: "You have deposited",
|
||||
no_transactions: "No recent transactions",
|
||||
transactions_trend: "Transactions Trend",
|
||||
total_transactions: "Total Transactions",
|
||||
accounts: "Accounts",
|
||||
account_number_copied: "Account number copied to clipboard",
|
||||
new_user_to_account: "New user to account",
|
||||
server_id: "Server ID",
|
||||
add_user: "Add User",
|
||||
new_account_name: "New Account Name",
|
||||
new_name: "New Name",
|
||||
rename: "Rename",
|
||||
create_new_account: "Create New Account",
|
||||
account_holder: "Account Holder",
|
||||
initial_balance: "Initial Balance",
|
||||
create: "Create",
|
||||
delete_account: "Delete Account",
|
||||
are_you_sure_you_want_to_delete_this_account:
|
||||
"Are you sure you want to delete this account?",
|
||||
delete: "Delete",
|
||||
remove_user_from_account: "Remove User from Account",
|
||||
select_user: "Select User",
|
||||
remove: "Remove",
|
||||
withdraw_from_account: "Withdraw from Account",
|
||||
deposit_to_account: "Deposit to Account",
|
||||
removed_successfully: "removed Successfully",
|
||||
select_account_and_user: "Please select an account and a user",
|
||||
account_deleted_successfully: "Account deleted successfully",
|
||||
new_account_created_successfully: "New account created successfully",
|
||||
withdrew: "Withdrew",
|
||||
successfully: "Successfully",
|
||||
select_valid_account_and_amount: "Please select a valid account and amount",
|
||||
openBank: "Access Bank",
|
||||
openATM: "Access ATM",
|
||||
account_deletion_failed: "Account deletion failed",
|
||||
withdrawal_failed: "Withdrawal failed",
|
||||
deposit_failed: "Deposit failed",
|
||||
user_added_successfully: "added successfully",
|
||||
user_addition_failed: "Failed to add user",
|
||||
new_account_creation_failed: "Failed to create new account",
|
||||
account_renamed_successfully: "Account renamed successfully",
|
||||
account_rename_failed: "Account rename failed",
|
||||
rename_account: "Change name",
|
||||
});
|
||||
|
||||
export const Transactions: Writable<Array<any>> = writable([
|
||||
// {
|
||||
// id: 8,
|
||||
// description: "Åbnede en ny konto",
|
||||
// type: "Fra konto",
|
||||
// amount: 1000,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isIncome: false,
|
||||
// },
|
||||
// {
|
||||
// id: 7,
|
||||
// description: "Indsatte 500 DKK på konto",
|
||||
// type: "Til konto",
|
||||
// amount: 500,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isIncome: true,
|
||||
// },
|
||||
// {
|
||||
// id: 6,
|
||||
// description: "Indsatte 500 DKK på konto",
|
||||
// type: "Til konto",
|
||||
// amount: 500,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isIncome: true,
|
||||
// },
|
||||
// {
|
||||
// id: 5,
|
||||
// description: "Hævede 500 DKK fra en hæveautomat",
|
||||
// type: "Fra konto",
|
||||
// amount: -500,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isIncome: false,
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// description: "Indsatte 500 DKK på konto",
|
||||
// type: "Til konto",
|
||||
// amount: 500,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isIncome: true,
|
||||
// },
|
||||
]);
|
||||
|
||||
export const Bills: Writable<Array<any>> = writable([
|
||||
// {
|
||||
// id: 1,
|
||||
// description: "Mekaniker Regning",
|
||||
// type: "Auto Exotic",
|
||||
// amount: 1000,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isPaid: false,
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// description: "Mekaniker Regning",
|
||||
// type: "Auto Exotic",
|
||||
// amount: 1000,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isPaid: false,
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// description: "Mekaniker Regning",
|
||||
// type: "Auto Exotic",
|
||||
// amount: 1000,
|
||||
// date: "2022/08/13",
|
||||
// timeAgo: "For 18 timer siden",
|
||||
// isPaid: false,
|
||||
// },
|
||||
]);
|
3
resources/[tools]/ps-banking/web/src/store/stores.ts
Normal file
3
resources/[tools]/ps-banking/web/src/store/stores.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { writable } from "svelte/store";
|
||||
|
||||
export const visibility = writable(false);
|
30
resources/[tools]/ps-banking/web/src/utils/debugData.ts
Normal file
30
resources/[tools]/ps-banking/web/src/utils/debugData.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {isEnvBrowser} from "./misc";
|
||||
|
||||
interface DebugEvent<T = any> {
|
||||
action: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates dispatching an event using SendNuiMessage in the lua scripts.
|
||||
* This is used when developing in browser
|
||||
*
|
||||
* @param events - The event you want to cover
|
||||
* @param timer - How long until it should trigger (ms)
|
||||
*/
|
||||
export const debugData = <P>(events: DebugEvent<P>[], timer = 1000): void => {
|
||||
if (isEnvBrowser()) {
|
||||
for (const event of events) {
|
||||
setTimeout(() => {
|
||||
window.dispatchEvent(
|
||||
new MessageEvent("message", {
|
||||
data: {
|
||||
action: event.action,
|
||||
data: event.data,
|
||||
},
|
||||
})
|
||||
);
|
||||
}, timer);
|
||||
}
|
||||
}
|
||||
};
|
27
resources/[tools]/ps-banking/web/src/utils/fetchNui.ts
Normal file
27
resources/[tools]/ps-banking/web/src/utils/fetchNui.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* @param eventName - The endpoint eventname to target
|
||||
* @param data - Data you wish to send in the NUI Callback
|
||||
*
|
||||
* @return returnData - A promise for the data sent back by the NuiCallbacks CB argument
|
||||
*/
|
||||
|
||||
export async function fetchNui<T = any>(
|
||||
eventName: string,
|
||||
data: unknown = {}
|
||||
): Promise<T> {
|
||||
const options = {
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
};
|
||||
|
||||
const resourceName = (window as any).GetParentResourceName
|
||||
? (window as any).GetParentResourceName()
|
||||
: "nui-frame-app";
|
||||
|
||||
const resp = await fetch(`https://${resourceName}/${eventName}`, options);
|
||||
|
||||
return await resp.json();
|
||||
}
|
1
resources/[tools]/ps-banking/web/src/utils/misc.ts
Normal file
1
resources/[tools]/ps-banking/web/src/utils/misc.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const isEnvBrowser = (): boolean => !(window as any).invokeNative;
|
51
resources/[tools]/ps-banking/web/src/utils/useNuiEvent.ts
Normal file
51
resources/[tools]/ps-banking/web/src/utils/useNuiEvent.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { onDestroy } from "svelte";
|
||||
|
||||
interface NuiMessage<T = unknown> {
|
||||
action: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that manage events listeners for receiving data from the client scripts
|
||||
* @param action The specific `action` that should be listened for.
|
||||
* @param handler The callback function that will handle data relayed by this function
|
||||
*
|
||||
* @example
|
||||
* useNuiEvent<{visibility: true, wasVisible: 'something'}>('setVisible', (data) => {
|
||||
* // whatever logic you want
|
||||
* })
|
||||
*
|
||||
**/
|
||||
|
||||
type NuiEventHandler<T = any> = (data: T) => void;
|
||||
|
||||
const eventListeners = new Map<string, NuiEventHandler[]>();
|
||||
|
||||
const eventListener = (event: MessageEvent<NuiMessage>) => {
|
||||
const { action, data } = event.data;
|
||||
const handlers = eventListeners.get(action);
|
||||
|
||||
if (handlers) {
|
||||
handlers.forEach((handler) => handler(data));
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("message", eventListener);
|
||||
|
||||
export function useNuiEvent<T = unknown>(
|
||||
action: string,
|
||||
handler: NuiEventHandler<T>
|
||||
) {
|
||||
const handlers = eventListeners.get(action) || [];
|
||||
handlers.push(handler);
|
||||
eventListeners.set(action, handlers);
|
||||
|
||||
onDestroy(() => {
|
||||
const handlers = eventListeners.get(action) || [];
|
||||
|
||||
eventListeners.set(
|
||||
action,
|
||||
handlers.filter((h) => h !== handler)
|
||||
);
|
||||
});
|
||||
}
|
2
resources/[tools]/ps-banking/web/src/vite-env.d.ts
vendored
Normal file
2
resources/[tools]/ps-banking/web/src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
8
resources/[tools]/ps-banking/web/svelte.config.js
Normal file
8
resources/[tools]/ps-banking/web/svelte.config.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
||||
import sveltePreprocess from "svelte-preprocess";
|
||||
|
||||
export default {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: [sveltePreprocess(), vitePreprocess({})],
|
||||
};
|
12
resources/[tools]/ps-banking/web/tailwind.config.cjs
Normal file
12
resources/[tools]/ps-banking/web/tailwind.config.cjs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/** @type {import('tailwindcss').Config}*/
|
||||
const config = {
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
module.exports = config;
|
25
resources/[tools]/ps-banking/web/tsconfig.json
Normal file
25
resources/[tools]/ps-banking/web/tsconfig.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"strict": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable checkJs if you'd like to use dynamic types in JS.
|
||||
* Note that setting allowJs false does not prevent the use
|
||||
* of JS in `.svelte` files.
|
||||
*/
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules/*", "public/*"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
8
resources/[tools]/ps-banking/web/tsconfig.node.json
Normal file
8
resources/[tools]/ps-banking/web/tsconfig.node.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node"
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
18
resources/[tools]/ps-banking/web/vite.config.ts
Normal file
18
resources/[tools]/ps-banking/web/vite.config.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
base: './',
|
||||
build: {
|
||||
minify: true,
|
||||
outDir: '../html',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
entryFileNames: '[name].js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].[ext]',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue