├── LICENSE
├── README.md
├── esx ver
└── rep-tablet
│ ├── INSTALL.md
│ ├── README.md
│ ├── Ui
│ ├── animate.min.css
│ ├── app.js
│ ├── groups.js
│ ├── imgs
│ │ ├── app
│ │ │ ├── facebook_app.png
│ │ │ ├── google_app.png
│ │ │ ├── instagram_app.png
│ │ │ ├── job_app.png
│ │ │ └── settings_app.png
│ │ ├── cloudy.png
│ │ ├── logo.png
│ │ ├── tablet.png
│ │ ├── tablet_background.png
│ │ ├── tablet_background2.png
│ │ └── tablet_job-background.png
│ ├── jobCenter.js
│ ├── jquery.min.js
│ ├── notify.css
│ ├── sounds
│ │ └── notify.ogg
│ ├── style.css
│ ├── twitter-style.css
│ └── ui.html
│ ├── client
│ ├── cl_group.lua
│ └── cl_main.lua
│ ├── config.lua
│ ├── fxmanifest.lua
│ └── server
│ └── sv_group.lua
└── qb-core ver
└── rep-tablet
├── .gitattributes
├── .vscode
└── settings.json
├── INSTALL.md
├── README.md
├── Ui
├── animate.min.css
├── app.js
├── groups.js
├── imgs
│ ├── app
│ │ ├── facebook_app.png
│ │ ├── google_app.png
│ │ ├── instagram_app.png
│ │ ├── job_app.png
│ │ └── settings_app.png
│ ├── cloudy.png
│ ├── logo.png
│ ├── tablet.png
│ ├── tablet_background.png
│ ├── tablet_background2.png
│ └── tablet_job-background.png
├── jobCenter.js
├── jquery.min.js
├── notify.css
├── sounds
│ └── notify.ogg
├── style.css
├── twitter-style.css
└── ui.html
├── client
├── cl_group.lua
└── cl_main.lua
├── config.lua
├── fxmanifest.lua
└── server
└── sv_group.lua
/README.md:
--------------------------------------------------------------------------------
1 | **[Preview](https://youtu.be/xuSjrBG-gRY)**
2 | **[Github](https://github.com/Rep-Scripts/rep-tablet)**
3 |
4 | _Discord Invite:_ https://discord.gg/VxGs8ceG5W
5 |
6 | _Tebex:_ https://rep.tebex.io/
7 |
8 | _Youtube:_ https://www.youtube.com/@repscripts
9 |
10 | _CFX:_ https://forum.cfx.re/u/bahnmifps/activity/topics
11 |
12 | > ## **INTRODUCTION**
13 |
14 | So, we make groups jobs. From the early versions of ps-playergroups since August 2022, to the latest qb-phone Nopixel inspired.
15 |
16 | However, these versions came with features that we didnt like, and 4 months later, we have released our own versions.
17 |
18 | The tablet is made so our customers who dont use qb-phone to enjoy our group jobs.
19 |
20 | **There are no jobs or anything included with these files.**
21 | **Check out the jobs at our Tebex.**
22 |
23 | ---
24 |
25 | > ## **FEATURES**
26 |
27 | ## **1. Job Center**
28 |
29 | - Configurable jobs, job location, money, icon, people to work, etc...
30 | - Navigate to assigned location.
31 | - "Illegal jobs" can be seen using a VPN.
32 | - Search bar for jobs
33 |
34 | ## **2. Groups**
35 |
36 | - Once signed in to jobs, players can see idle/busy groups.
37 | - Can create groups with up to 4 members.
38 | - If has VPN, players names will be automatically generated to cover their identity.
39 |
40 | ## **3. Syncing**
41 |
42 | - Sync job progress between players.
43 | - Sync notifications and job details.
44 |
45 | ---
46 |
47 | > ## **INSTALLATION**
48 |
49 | Drag and drop...
50 |
51 | ---
52 |
53 | > ## **🛠️ UPDATES**
54 |
55 | **Update 1.0**
56 |
57 | - Release
58 |
59 | ---
60 |
61 | **Update 1.1**
62 |
63 | - _to be updated_
64 |
65 | ---
66 |
67 | > ## **DEPENDENCIES**
68 |
69 | - [QBcore Framework](https://github.com/qbcore-framework)
70 | - [ESX](https://github.com/esx-framework)
71 |
72 | ---
73 |
74 | > ## **Check out our other products** :star2:
75 |
76 | - [[QB/ESX] Group Postal Op Delivery. NoPixel 3.5 DoDo Inspired](https://forum.cfx.re/t/qb-esx-group-postal-op-delivery-nopixel-3-5-dodo-inspired/4894624/29)
77 | - [NoPixel Inspired Group Sanitation Job v2](https://forum.cfx.re/t/nopixel-inspired-group-sanitation-job-v2/4929184/5)
78 | - [NoPixel Inspired Oxy Run w/ Money Laundering](https://forum.cfx.re/t/nopixel-inspired-oxy-run-w-money-laundering/4941107/10)
79 | - [NoPixel Inspired Chop Shop. With Phone Progresses!](https://forum.cfx.re/t/nopixel-inspired-chop-shop-with-phone-progresses/4942864/5)
80 | - [[PAID] [QBCORE] Advanced Realistic Trunk Space](https://forum.cfx.re/t/paid-qbcore-advanced-realistic-trunk-space/4891965/2)
81 | - [[RELEASE] [PAID] QBCore Realistic Vehiclekey with Hacking Device](https://forum.cfx.re/t/release-paid-qbcore-realistic-vehiclekey-with-hacking-device/4891955/10)
82 |
83 | > ## **DMCA Protection Certificate**
84 | >
85 | > https://i.imgur.com/DMh5xiO.png
86 | > https://www.dmca.com/r/597rj6e
87 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/INSTALL.md:
--------------------------------------------------------------------------------
1 | Made by Rep Scripts
2 | Discord: https://discord.gg/WK7nYmDhrN (24/7 support and updates)
3 | Tebex: https://rep.tebex.io/
4 |
5 | # Dependencies
6 |
7 | - [QBCore Framework](https://github.com/qbcore-framework)
8 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/README.md:
--------------------------------------------------------------------------------
1 | **[Preview](https://youtu.be/xuSjrBG-gRY)**
2 | **[Github](https://github.com/Rep-Scripts/rep-tablet)**
3 |
4 | _Discord Invite:_ https://discord.gg/VxGs8ceG5W
5 |
6 | _Tebex:_ https://rep.tebex.io/
7 |
8 | _Youtube:_ https://www.youtube.com/@repscripts
9 |
10 | _CFX:_ https://forum.cfx.re/u/bahnmifps/activity/topics
11 |
12 | > ## **INTRODUCTION**
13 |
14 | So, we make groups jobs. From the early versions of ps-playergroups since August 2022, to the latest qb-phone Nopixel inspired.
15 |
16 | However, these versions came with features that we didnt like, and 4 months later, we have released our own versions.
17 |
18 | The tablet is made so our customers who dont use qb-phone to enjoy our group jobs.
19 |
20 | **There are no jobs or anything included with these files.**
21 | **Check out the jobs at our Tebex.**
22 |
23 | ---
24 |
25 | > ## **FEATURES**
26 |
27 | ## **1. Job Center**
28 |
29 | - Configurable jobs, job location, money, icon, people to work, etc...
30 | - Navigate to assigned location.
31 | - "Illegal jobs" can be seen using a VPN.
32 | - Search bar for jobs
33 |
34 | ## **2. Groups**
35 |
36 | - Once signed in to jobs, players can see idle/busy groups.
37 | - Can create groups with up to 4 members.
38 | - If has VPN, players names will be automatically generated to cover their identity.
39 |
40 | ## **3. Syncing**
41 |
42 | - Sync job progress between players.
43 | - Sync notifications and job details.
44 |
45 | ---
46 |
47 | > ## **INSTALLATION**
48 |
49 | Drag and drop...
50 |
51 | ---
52 |
53 | > ## **🛠️ UPDATES**
54 |
55 | **Update 1.0**
56 |
57 | - Release
58 |
59 | ---
60 |
61 | **Update 1.1**
62 |
63 | - _to be updated_
64 |
65 | ---
66 |
67 | > ## **DEPENDENCIES**
68 |
69 | - [QBcore Framework](https://github.com/qbcore-framework)
70 | - [ESX](https://github.com/esx-framework)
71 |
72 | ---
73 |
74 | > ## **Check out our other products** :star2:
75 |
76 | - [[QB/ESX] Group Postal Op Delivery. NoPixel 3.5 DoDo Inspired](https://forum.cfx.re/t/qb-esx-group-postal-op-delivery-nopixel-3-5-dodo-inspired/4894624/29)
77 | - [NoPixel Inspired Group Sanitation Job v2](https://forum.cfx.re/t/nopixel-inspired-group-sanitation-job-v2/4929184/5)
78 | - [NoPixel Inspired Oxy Run w/ Money Laundering](https://forum.cfx.re/t/nopixel-inspired-oxy-run-w-money-laundering/4941107/10)
79 | - [NoPixel Inspired Chop Shop. With Phone Progresses!](https://forum.cfx.re/t/nopixel-inspired-chop-shop-with-phone-progresses/4942864/5)
80 | - [[PAID] [QBCORE] Advanced Realistic Trunk Space](https://forum.cfx.re/t/paid-qbcore-advanced-realistic-trunk-space/4891965/2)
81 | - [[RELEASE] [PAID] QBCore Realistic Vehiclekey with Hacking Device](https://forum.cfx.re/t/release-paid-qbcore-realistic-vehiclekey-with-hacking-device/4891955/10)
82 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/app.js:
--------------------------------------------------------------------------------
1 | REP = {};
2 | REP.Tablet = {};
3 | REP.Tablet.Functions = {};
4 | REP.Tablet.Animations = {};
5 | REP.Tablet.Notifications = {};
6 | REP.Tablet.Notifications.Custom = {};
7 |
8 | REP.Tablet.Data = {
9 | isOpen: false,
10 | PlayerData: {},
11 | };
12 |
13 | REP.Tablet.Config = {}
14 | var found = false;
15 |
16 | $(function() {
17 | $(".success_icon").hide();
18 | $("#job-app").on("click", function(e) {
19 | e.preventDefault();
20 | LoadJobCenter();
21 | });
22 |
23 | $(".tablet__back--mainscreen").on("click", function() {
24 | $("#job-screen").fadeOut("1500");
25 | $("#create-screen").fadeOut("1500");
26 | $("#group-screen").fadeOut("1500");
27 | $("#tasks-screen").fadeOut("1500");
28 | $("#main-screen").show();
29 | });
30 |
31 | $("#date").html(getDate());
32 | $(".tablet__info h3").html(getTime());
33 |
34 | REP.Tablet.Functions.OpenTablet = function() {
35 | $("#tablet").fadeIn("1500");
36 | REP.Tablet.Data.IsOpen = true;
37 | };
38 |
39 | REP.Tablet.Functions.CloseTablet = function() {
40 | // $("#job-screen").fadeOut("1500");
41 | // $("#create-screen").fadeOut("1500");
42 | // $("#group-screen").fadeOut("1500");
43 | // $("#tasks-screen").fadeOut("1500");
44 | $("#tablet").fadeOut("1500");
45 | $.post('https://rep-tablet/Close');
46 | REP.Tablet.Data.IsOpen = false;
47 | };
48 |
49 | REP.Tablet.Animations.BottomSlideUp = function(Object, Timeout, Percentage) {
50 | $(Object).css({'display':'block'}).animate({
51 | bottom: Percentage+"%",
52 | }, Timeout);
53 | };
54 |
55 | REP.Tablet.Animations.BottomSlideDown = function(Object, Timeout, Percentage) {
56 | $(Object).css({'display':'block'}).animate({
57 | bottom: Percentage+"%",
58 | }, Timeout, function(){
59 | $(Object).css({'display':'none'});
60 | });
61 | };
62 |
63 | REP.Tablet.Animations.TopSlideDown = function(Object, Timeout, Percentage) {
64 | $(Object).css({'display':'block'}).animate({
65 | top: Percentage+"%",
66 | }, Timeout);
67 | };
68 |
69 | REP.Tablet.Animations.TopSlideUp = function(Object, Timeout, Percentage) {
70 | $(Object).css({'display':'block'}).animate({
71 | top: Percentage+"%",
72 | }, Timeout, function(){
73 | $(Object).css({'display':'none'});
74 | });
75 | };
76 |
77 | REP.Tablet.Animations.fadeInAnim = function(Object, Timeout) {
78 | $(Object).css({
79 | 'display': 'block',
80 | 'opacity': '1',
81 | 'transition': 'opacity .25s ease'
82 | }, Timeout);
83 | };
84 |
85 | REP.Tablet.Animations.fadeOutAnim = function(Object, Timeout) {
86 | $(Object).css({
87 | 'display': 'block',
88 | 'opacity': '0',
89 | 'transition': 'opacity .25s ease'
90 | }, Timeout, function(){
91 | $(Object).css({'display':'none'});
92 | });
93 | };
94 |
95 | REP.Tablet.Functions.LoadPlayerData = function(data) {
96 | REP.Tablet.Data.PlayerData = data;
97 |
98 | }
99 |
100 | REP.Tablet.Functions.LoadConfig = function(data) {
101 | REP.Tablet.Config = data;
102 | }
103 |
104 |
105 | REP.Tablet.Notifications.Custom.Add = function(icon, title, text, color, timeout, accept, deny) {
106 | $.post('https://rep-tablet/HasTablet', JSON.stringify({}), function(HasTablet) {
107 | if (HasTablet) {
108 | if (REP.Tablet.Notifications.Timeout !== undefined && REP.Tablet.Notifications.Timeout !== null) {
109 | clearTimeout(REP.Tablet.Notifications.Timeout);
110 | }
111 | REP.Tablet.Notifications.Timeout = null;
112 |
113 | if (timeout == null || timeout == undefined) {
114 | timeout = 1500;
115 | }
116 | if (color != null && color != undefined) {
117 | $(".notification-icon-new").css({"color": color});
118 | $(".notification-title-new").css({"color":"#FFFFFF"});
119 |
120 | } else if (color == "default" || color == null || color == undefined) {
121 | $(".notification-icon-new").css({"color":"#FFFFFF"});
122 | $(".notification-title-new").css({"color":"#FFFFFF"});
123 | }
124 | playSound("notify.ogg", "./sounds/", 0.6);
125 | REP.Tablet.Animations.TopSlideDown(".__tablet--notification-container-new", 600, 1);
126 | $(".notification-icon-new").html(' ');
127 | $(".notification-title-new").html(title);
128 | $(".notification-text-new").html(text);
129 | $(".notification-time-new").html("just now");
130 | if (accept != "NONE"){
131 | $(".notification-accept").html(' ');
132 | }
133 | if (deny != "NONE"){
134 | $(".notification-deny").html(' ');
135 | }
136 |
137 | if (timeout != "NONE"){
138 | if (REP.Tablet.Notifications.Timeout !== undefined && REP.Tablet.Notifications.Timeout !== null) {
139 | clearTimeout(REP.Tablet.Notifications.Timeout);
140 | }
141 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
142 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
143 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
144 | }, 500)
145 | REP.Tablet.Notifications.Timeout = null;
146 | }, timeout);
147 | };
148 | };
149 | });
150 | };
151 |
152 | REP.Tablet.Notifications.Add = function(icon, title, text, color, timeout) {
153 | $.post('https://rep-tablet/HasTablet', JSON.stringify({}), function(HasTablet) {
154 | if(HasTablet) {
155 | if (timeout == null && timeout == undefined) {
156 | timeout = 1500;
157 | }
158 |
159 | if (REP.Tablet.Notifications.Timeout == undefined || REP.Tablet.Notifications.Timeout == null) {
160 | if (color != null || color != undefined) {
161 | $(".notification-icon").css({"color":color});
162 | $(".notification-title").css({"color":color});
163 | } else if (color == "default" || color == null || color == undefined) {
164 | $(".notification-icon").css({"color":"#e74c3c"});
165 | $(".notification-title").css({"color":"#e74c3c"});
166 | }
167 |
168 | REP.Tablet.Animations.TopSlideDown(".__tablet--notification-container", 600, 1);
169 | $(".notification-icon").html(' ');
170 | $(".notification-title").html(title);
171 | $(".notification-text").html(text);
172 | $(".notification-time").html("just now");
173 | if (timeout != "NONE"){
174 | if (REP.Tablet.Notifications.Timeout !== undefined || REP.Tablet.Notifications.Timeout !== null) {
175 | clearTimeout(REP.Tablet.Notifications.Timeout);
176 | }
177 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
178 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
179 |
180 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
181 |
182 | }, 500)
183 | REP.Tablet.Notifications.Timeout = null;
184 | }, timeout);
185 | }
186 | } else {
187 | if (color != null || color != undefined) {
188 | $(".notification-icon").css({"color":color});
189 | $(".notification-title").css({"color":color});
190 | } else {
191 | $(".notification-icon").css({"color":"#e74c3c"});
192 | $(".notification-title").css({"color":"#e74c3c"});
193 | }
194 |
195 | $(".notification-icon").html(' ');
196 | $(".notification-title").html(title);
197 | $(".notification-text").html(text);
198 | $(".notification-time").html("just now");
199 | if (timeout != "NONE"){
200 | if (REP.Tablet.Notifications.Timeout !== undefined || REP.Tablet.Notifications.Timeout !== null) {
201 | clearTimeout(REP.Tablet.Notifications.Timeout);
202 | }
203 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
204 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
205 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
206 |
207 | }, 500)
208 | REP.Tablet.Notifications.Timeout = null;
209 | }, timeout);
210 | }
211 | }
212 | }
213 | });
214 | }
215 |
216 | $(document).on('click', ".__tablet--notification-container", function() {
217 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
218 | REP.Tablet.Notifications.Timeout = null;
219 | })
220 |
221 | $(document).on('click', ".notification-accept", function() {
222 | $.post('https://rep-tablet/AcceptNotification', JSON.stringify({}));
223 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
224 | REP.Tablet.Notifications.Timeout = null;
225 | });
226 |
227 | $(document).on('click', ".notification-deny", function() {
228 | $.post('https://rep-tablet/DenyNotification', JSON.stringify({}));
229 | REP.Tablet.Notifications.Timeout = null;
230 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
231 | });
232 |
233 | $("body").on("keyup", function (e) {
234 | if (e.which == 27) {
235 | REP.Tablet.Functions.CloseTablet();
236 | };
237 | });
238 |
239 | window.addEventListener('message', function(e) {
240 | if (e.data.action === 'open') {
241 | $("#user-name").html(e.data.name);
242 | REP.Tablet.Functions.LoadPlayerData(e.data.data);
243 | REP.Tablet.Functions.OpenTablet();
244 | REP.Tablet.Data.isOpen = true;
245 | } else if (e.data.action === 'CustomNotification') {
246 | REP.Tablet.Notifications.Add(e.data.TabletNotify.icon, e.data.TabletNotify.title, e.data.TabletNotify.text, e.data.TabletNotify.color, e.data.TabletNotify.timeout);
247 | } else if (e.data.action === 'loadConfig') {
248 | REP.Tablet.Functions.LoadConfig(e.data.config);
249 | } else if (e.data.action === 'ReQuest') {
250 | REP.Tablet.Notifications.Custom.Add(e.data.TabletNotify.icon, e.data.TabletNotify.title, e.data.TabletNotify.text, e.data.TabletNotify.color, e.data.TabletNotify.timeout, e.data.TabletNotify.accept, e.data.TabletNotify.deny);
251 | } else if (e.data.action==='closeCustomNotification'){
252 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
253 | } else if (e.data.action === 'closeAllNotification'){
254 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
255 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
256 | }
257 | });
258 |
259 | function getDate() {
260 | var date = new Date();
261 | var day = date.getDay();
262 | var fristDay = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
263 | var month = (date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : (date.getMonth() + 1);
264 | var year = date.getFullYear();
265 | var dayArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
266 | var occasion = dayArray[day];
267 | var currentDate = occasion + ", " + fristDay + "/" + month + "/" + year;
268 | return currentDate;
269 | };
270 |
271 | function getTime() {
272 | var date = new Date();
273 | var hour = date.getHours();
274 | var minute = date.getMinutes();
275 | var amOrPm = hour >= 12 ? 'PM' : 'AM';
276 | hour = hour % 12;
277 | hour = hour ? hour : 12;
278 | minute = minute < 10 ? '0'+ minute : minute;
279 | var strTime = `${hour}:${minute} ${amOrPm} `;
280 | return strTime;
281 | };
282 |
283 | $("#search").on("keyup", function() {
284 | var value = $(this).val().toLowerCase();
285 | $(".tablet__job--item").filter(function() {
286 | $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
287 | });
288 | });
289 | });
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/groups.js:
--------------------------------------------------------------------------------
1 | var loadScreen = 7500; // Dont Touch This
2 | var loadSuccess = 6000; // Dont Touch This
3 | var min = 5000; // 5 seconds
4 | var max = 10000; // 10 seconds
5 | var minutes = 00;
6 | var seconds = 00;
7 | var tens = 00;
8 | var appendTens = document.getElementById("tens");
9 | var appendSeconds = document.getElementById("seconds");
10 | var appendminutes = document.getElementById("minutes");
11 | var Interval;
12 | var groupID;
13 | var data1;
14 | var data2;
15 | var jobPlayer;
16 | var randomTime = Math.floor(Math.random() * (max - min + 1)) + min;
17 | let notReadyButtonAdded = false;
18 |
19 | $(document).on("click", "#create-group", function(e) {
20 | e.preventDefault();
21 | $("#main-screen").hide();
22 | $("#create-screen").hide();
23 | $(".success_icon").hide();
24 | $(".text p").html("Please Wait...");
25 | $(".loader__wrapper").show();
26 | $("#loader-screen").show();
27 | setTimeout(function() {
28 | $(".loader__wrapper").hide();
29 | $(".success_icon").show();
30 | $(".text p").html("Created successfully!");
31 | }, loadSuccess);
32 | setTimeout(function() {
33 | $("#loader-screen").fadeOut("1500");
34 | $("#group-screen").fadeIn("1500");
35 | $.post("https://rep-tablet/CreateJobGroup", JSON.stringify({}), function() {});
36 | }, loadScreen);
37 | });
38 |
39 | function showNotification() {
40 | playSound("notify.ogg", "./sounds/", 0.6);
41 | $.post("https://rep-tablet/readyToJob", JSON.stringify({}), function() {});
42 | }
43 |
44 | function playSound(file, dir, volume) {
45 | var audio = new Audio(dir+file);
46 | audio.volume = volume;
47 | audio.play();
48 | }
49 |
50 | function closeAllScreen() {
51 | $("#job-screen").hide();
52 | $("#create-screen").hide();
53 | $("#group-screen").hide();
54 | $("#tasks-screen").hide();
55 | }
56 |
57 | $(document).on("click", "#check-out", function(e) {
58 | e.preventDefault();
59 | $.post("https://rep-tablet/checkOut", JSON.stringify({}), function() {});
60 | });
61 |
62 | $(document).on("click", "#job-ready", function(e) {
63 | e.preventDefault();
64 | $("#job-ready").addClass("checked");
65 | $("#job-ready p").text("waiting for job...");
66 | $(".spinner").removeClass("bxs-briefcase").addClass("bx-loader-alt spin");
67 |
68 | if (!$("#job-notready").length) {
69 | $("#room-actions").append(
70 | '' +
71 | 'not ready
' +
72 | ' ' +
73 | ' '
74 | );
75 | }
76 | setTimeout(showNotification, REP.Tablet.Config[jobPlayer].time.first);
77 | });
78 |
79 | $(document).on("click", "#job-notready", function(e) {
80 | e.preventDefault();
81 | $("#job-ready").removeClass("checked");
82 | $("#job-ready p").text("ready for work");
83 | $(".spinner").removeClass("bx-loader-alt spin").addClass("bxs-briefcase");
84 | $("#job-notready").remove();
85 | notReadyButtonAdded = false;
86 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
87 | });
88 |
89 | $(document).on("click", "#join-group", function (e) {
90 | e.preventDefault();
91 | var id = $(this).data('id');
92 | $.post("https://rep-tablet/RequestToJoin", JSON.stringify({id: id}), function() {});
93 | });
94 |
95 | $(document).on("click", "#disband-group", function(e) {
96 | var id = $(this).data('id');
97 | $.post("https://rep-tablet/DisbandGroup", JSON.stringify({id: id}), function() {});
98 | });
99 |
100 | $(document).on("click", "#leave-group", function(e) {
101 | var id = $(this).data('id');
102 | $.post("https://rep-tablet/LeaveGroup", JSON.stringify({id: id}), function() {});
103 | });
104 |
105 | $(document).on("click", "#expand-modal", function(e) {
106 | e.preventDefault();
107 | $("#task-overlay").fadeIn("1500");
108 | $("#task-modal").fadeIn("1500");
109 | });
110 |
111 | $(document).on("click", "#task-close", function(e) {
112 | e.preventDefault();
113 | $("#task-overlay").fadeOut("1500");
114 | $("#task-modal").fadeOut("1500");
115 | });
116 |
117 | function addGroupJobs(data) {
118 | if (data.status == true) {
119 | closeAllScreen();
120 | $("#tasks-screen").show();
121 | let tasksPerRow = 2;
122 | $("#tasks-list").html("");
123 | clearInterval(Interval);
124 | Interval = setInterval(startTimer, 10);
125 | let rowHTML = '';
126 | let taskCounter = 0;
127 | for (const [k, v] of Object.entries(data.stage)) {
128 | let max = 1;
129 | let count = 0;
130 | if (v.max) max = v.max;
131 | if (v.count) count = v.count;
132 |
133 | if (taskCounter % tasksPerRow === 0) {
134 | rowHTML += '
';
135 | }
136 |
137 | let addOption;
138 | if (v.isDone) {
139 | addOption =
140 | `
141 |
142 |
143 |
144 |
${v.name}
145 |
146 |
147 |
${max} / ${max}
148 |
149 |
150 | `;
151 | } else {
152 | addOption =
153 | `
154 |
155 |
156 |
157 |
${v.name}
158 |
159 |
160 |
${count} / ${max}
161 |
162 |
163 | `;
164 | }
165 |
166 |
167 | rowHTML += addOption;
168 | taskCounter++;
169 |
170 | if (taskCounter % tasksPerRow === 0) {
171 | rowHTML += '
';
172 | } else {
173 | rowHTML += '
';
174 | }
175 | $(".__tablet--modal-content").html(v.name);
176 | }
177 | $("#tasks-list").append(rowHTML);
178 | } else {
179 | closeAllScreen();
180 | $("#group-screen").show();
181 | var memberList = $('.__tablet--member-list');
182 | memberList.html("");
183 | var itemCounter = 0;
184 | var rowHTML = '';
185 | var leaderName = "";
186 | var leaderCID = 0
187 | for (const [k, v] of Object.entries(data.members)) {
188 | if (v.player === data.leader) {
189 | leaderName = v.name;
190 | leaderCID = v.cid;
191 | }
192 | }
193 | var leaderHTML = '
';
194 | leaderHTML += '
';
195 | leaderHTML += '
leader
';
196 | leaderHTML += '
' + leaderName + '
';
197 | leaderHTML += '
';
198 | leaderHTML += '
';
199 | rowHTML += leaderHTML;
200 | itemCounter++;
201 |
202 | for (const [k, v] of Object.entries(data.members)) {
203 | if (k > 0) {
204 | var memberHTML = '
';
205 | memberHTML += '
';
206 | memberHTML += '
member
';
207 | memberHTML += '
' + v.name + '
';
208 | memberHTML += '
';
209 | memberHTML += '
';
210 | rowHTML += memberHTML;
211 | itemCounter++;
212 |
213 | if (itemCounter == 4) {
214 | rowHTML += '
';
215 | memberList.append(rowHTML);
216 | rowHTML = '';
217 | itemCounter = 0;
218 | }
219 | }
220 | }
221 | var ctd = REP.Tablet.Data.PlayerData.identifier;
222 | if (ctd !== leaderCID) {
223 | $("#room-actions").html('
' +
224 | 'leave group
' +
225 | ' ' +
226 | ' ');
227 | } else {
228 | $("#room-actions").html(
229 | '
' +
230 | 'ready for work
' +
231 | ' ' +
232 | ' ' +
233 | '
' +
234 | 'disband group
' +
235 | ' ' +
236 | ' '
237 | );
238 | }
239 | if (itemCounter > 0) {
240 | rowHTML += '
';
241 | memberList.append(rowHTML);
242 | };
243 | };
244 | };
245 |
246 | function addGroup(data, job) {
247 | var addOption;
248 | var addOption1;
249 | var row = ``;
250 | var row1 = `
`;
251 | var idleList = $("#group-idle");
252 | var idle = 0;
253 | var busy = 0;
254 | idleList.html("");
255 | var busyList = $("#group-busy");
256 | busyList.html("");
257 | if (data && data.length > 0) {
258 | Object.keys(data).map(function(element) {
259 | if (data[element]) {
260 | if (!data[element].status && data[element].job === job) {
261 | idle = idle + 1;
262 | addOption = `
263 |
264 |
265 |
266 |
${data[element].gName}
267 |
268 |
269 |
270 |
271 |
${REP.Tablet.Config[job].mem}
272 |
273 |
274 |
275 |
${data[element].users}
276 |
277 |
278 |
279 |
280 |
join group
281 |
282 |
283 | `;
284 | row += addOption;
285 | if (idle % 3 === 0) {
286 | row += '
';
287 | idleList.append(row);
288 | row = `
`;
289 | }
290 | } else if (data[element].status && data[element].job === job) {
291 | busy = busy + 1;
292 | addOption1 =
293 | `
294 |
295 |
296 |
297 |
${data[element].gName}
298 |
299 |
300 |
301 |
302 |
${REP.Tablet.Config[job].mem}
303 |
304 |
305 |
306 |
${data[element].users}
307 |
308 |
309 |
310 | `;
311 | row1 += addOption1;
312 | if (busy % 3 === 0) {
313 | row1 += '
';
314 | busyList.append(row1);
315 | row1 = `
`;
316 | }
317 | }
318 | }
319 | });
320 | row += '
'; // Add closing tag for idle row
321 | idleList.append(row);
322 | row1 += '
'; // Add closing tag for busy row
323 | busyList.append(row1);
324 |
325 | if (idle === 0) {
326 | idleList.html(`There are no idle groups available
`);
327 | }
328 | if (busy === 0) {
329 | busyList.html(`There are no busy groups available
`);
330 | }
331 | } else {
332 | idleList.html(`There are no idle groups available
`);
333 | busyList.html(`There are no busy groups available
`);
334 | }
335 | };
336 |
337 | function startTimer() {
338 | tens++;
339 | if(tens <= 9){
340 | appendTens.innerHTML = "0" + tens;
341 | }
342 |
343 | if (tens > 9){
344 | appendTens.innerHTML = tens;
345 |
346 | }
347 |
348 | if (tens > 99) {
349 | seconds++;
350 | appendSeconds.innerHTML = "0" + seconds;
351 | tens = 0;
352 | appendTens.innerHTML = "0" + 0;
353 | }
354 |
355 | if (seconds > 9){
356 | appendSeconds.innerHTML = seconds;
357 | }
358 |
359 | if (seconds > 60){
360 | minutes++;
361 | appendminutes.innerHTML = "0" + minutes;
362 | seconds = 0;
363 | appendSeconds.innerHTML = "0" + 0;
364 | }
365 | };
366 |
367 | $(function() {
368 | window.addEventListener('message', function(e) {
369 | if (e.data.action === 'refreshApp') {
370 | closeAllScreen();
371 | jobPlayer = e.data.job;
372 | $("#create-screen").fadeIn("1500");
373 | if (REP.Tablet.Config[e.data.job]) {
374 | $(".__tablet--header-content").html(REP.Tablet.Config[e.data.job].label);
375 | }
376 | addGroup(e.data.data, e.data.job);
377 | } else if (e.data.action === 'addGroupStage') {
378 | addGroupJobs(e.data.status);
379 | } else if (e.data.action === 'reLoop') {
380 | setTimeout(showNotification, REP.Tablet.Config[jobPlayer].time.second);
381 | } else if (e.data.action === 'cancelReady') {
382 | e.preventDefault();
383 | $("#job-ready").removeClass("checked");
384 | $("#job-ready p").text("ready for work");
385 | $(".spinner").removeClass("bx-loader-alt spin").addClass("bxs-briefcase");
386 | $("#job-notready").remove();
387 | notReadyButtonAdded = false;
388 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
389 | }
390 | });
391 | });
392 |
393 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/app/facebook_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/app/facebook_app.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/app/google_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/app/google_app.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/app/instagram_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/app/instagram_app.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/app/job_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/app/job_app.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/app/settings_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/app/settings_app.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/cloudy.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/logo.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/tablet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/tablet.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/tablet_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/tablet_background.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/tablet_background2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/tablet_background2.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/imgs/tablet_job-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/imgs/tablet_job-background.png
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/jobCenter.js:
--------------------------------------------------------------------------------
1 | $(document).on("click", "#get-location", function (e) {
2 | e.preventDefault();
3 | var event = $(this).data("event");
4 | $.post("https://rep-tablet/CreateBlip", JSON.stringify({
5 | event: event,
6 | }));
7 | });
8 |
9 | function addJobsList(data) {
10 | $(".tablet__job--list").html("");
11 | for (let i = 0; i < data.length; i++) {
12 | const v = data[i];
13 | var addOption =
14 | `
15 |
16 |
17 |
18 |
19 |
20 |
${v.label}
21 |
22 |
23 |
24 | ${v.salary}
25 |
26 |
27 |
28 |
29 | ${v.mem}
30 |
31 |
32 |
33 |
34 | ${v.count}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
get location
42 |
43 |
`;
44 | $(".tablet__job--list").append(addOption);
45 | };
46 | };
47 |
48 | function LoadJobCenter() {
49 | $.post('https://rep-tablet/GetData', JSON.stringify({}), function() {});
50 | };
51 |
52 | $(function() {
53 | window.addEventListener('message', function(e) {
54 | if (e.data.action === 'jobcenter') {
55 | closeAllScreen();
56 | $("#job-screen").fadeIn("1500");
57 | addJobsList(e.data.data);
58 | };
59 | });
60 | });
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/notify.css:
--------------------------------------------------------------------------------
1 | .__tablet--notification-container,
2 | .__tablet--notification-container-new {
3 | position: absolute;
4 | height: 7vh;
5 | width: 40vh;
6 | background: rgba(58, 65, 71, 0.806);
7 | margin: 0 auto;
8 | left: 0;
9 | right: 0;
10 | top: -10%;
11 | overflow: hidden;
12 | box-shadow: inset 0px 0px 10px 0px rgba(0, 0, 0, 0.11);
13 | z-index: 9999999999;
14 | border-radius: .4vw;
15 | padding: 1.2vh 1vw;
16 | }
17 |
18 | .__tablet--notification-top {
19 | display: flex;
20 | align-items: center;
21 | width: 100%;
22 | justify-content: space-between;
23 | margin-bottom: .48vh;
24 | }
25 |
26 | .__tablet--notification-container-new .__tablet--notification-top {
27 | margin-bottom: .25vh;
28 | }
29 |
30 | .__tablet--notification-item {
31 | display: flex;
32 | align-items: center;
33 | width: 50%;
34 | gap: .5vw;
35 | }
36 |
37 | .notification-icon,
38 | .notification-icon-new {
39 | width: 3vh;
40 | height: 50%;
41 | text-align: center;
42 | line-height: 2.8vh;
43 | color: var(--white-color);
44 | font-size: 2.4vh;
45 | }
46 |
47 | .notification-title,
48 | .notification-title-new {
49 | font-size: 1.5vh;
50 | color: var(--white-color);
51 | text-transform: var(--main-font-transform);
52 | font-weight: 600;
53 | }
54 |
55 | .notification-time,
56 | .notification-time-new {
57 | font-size: 1.5vh;
58 | color: rgb(255, 255, 255);
59 | text-transform: capitalize;
60 | }
61 |
62 | .notification-text,
63 | .notification-text-new {
64 | font-size: 1.4vh;
65 | color: rgb(255, 255, 255);
66 | white-space: nowrap;
67 | overflow: hidden;
68 | text-overflow: ellipsis;
69 | text-align: left;
70 | }
71 |
72 | .notification-text {
73 | max-width: 100%;
74 | }
75 |
76 | .notification-text-new {
77 | max-width: 65%;
78 | }
79 |
80 | .__tablet--notification-bottom {
81 | width: 100%;
82 | display: flex;
83 | align-items: center;
84 | justify-content: space-between;
85 | }
86 |
87 | .__tablet--notification-btn {
88 | display: flex;
89 | align-items: center;
90 | gap: .25vw;
91 | }
92 |
93 | .__tablet--notification-btn > * {
94 | transition: .25s ease;
95 | }
96 |
97 | .notification-accept {
98 | font-size: 1.9vh;
99 | color: rgb(26, 176, 26);
100 | cursor: pointer;
101 | }
102 |
103 | .notification-accept:hover {
104 | color: rgb(34, 233, 34);
105 | }
106 |
107 | .notification-deny {
108 | font-size: 1.9vh;
109 | color: rgb(201, 28, 28);
110 | cursor: pointer;
111 | }
112 |
113 | .notification-deny:hover {
114 | color: rgb(238, 33, 33);
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/sounds/notify.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/esx ver/rep-tablet/Ui/sounds/notify.ogg
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/twitter-style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Barlow&display=swap');
2 | @import url('https://fonts.googleapis.com/css2?family=Quicksand&display=swap');
3 | @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
4 | @import url("./animate.min.css");
5 |
6 | * {
7 | -webkit-box-sizing: border-box;
8 | -moz-box-sizing: border-box;
9 | box-sizing: border-box;
10 | -moz-user-select: none;
11 | -khtml-user-select: none;
12 | -webkit-user-select: none;
13 | -ms-user-select: none;
14 | user-select: none;
15 | list-style: none;
16 | text-decoration: none;
17 | font-family: 'Roboto', sans-serif;
18 | }
19 |
20 | :root {
21 | --main-font-transform: uppercase;
22 | --main-light-font: 400;
23 | --main-bold-font: 700;
24 | --white-color: #F5F8FA;
25 | --color-2: rgb(188, 188, 188);
26 | }
27 |
28 | html {
29 | font-size: 62.5%;
30 | }
31 |
32 | html, body {
33 | height: 100%;
34 | }
35 |
36 | body {
37 | margin: 0;
38 | padding: 0;
39 | overflow: hidden;
40 | }
41 |
42 | .animate__animated.animate__delay-1s {
43 | -webkit-animation-delay: .1s;
44 | animation-delay: .1s;
45 | }
46 |
47 | .animate__animated.animate__delay-2s {
48 | -webkit-animation-delay: .2s;
49 | animation-delay: .2s;
50 | }
51 |
52 | .animate__animated.animate__delay-3s {
53 | -webkit-animation-delay: .3s;
54 | animation-delay: .3s;
55 | }
56 |
57 | .animate__animated.animate__delay-4s {
58 | -webkit-animation-delay: .4s;
59 | animation-delay: .4s;
60 | }
61 |
62 | .animate__animated.animate__delay-5s {
63 | -webkit-animation-delay: .5s;
64 | animation-delay: .5s;
65 | }
66 |
67 | .animate__animated.animate__delay-6s {
68 | -webkit-animation-delay: .6s;
69 | animation-delay: .6s;
70 | }
71 |
72 | .animate__animated.animate__delay-7s {
73 | -webkit-animation-delay: .7s;
74 | animation-delay: .7s;
75 | }
76 |
77 | .animate__animated.animate__delay-8s {
78 | -webkit-animation-delay: .8s;
79 | animation-delay: .8s;
80 | }
81 |
82 | .animate__animated.animate__delay-9s {
83 | -webkit-animation-delay: .9s;
84 | animation-delay: .9s;
85 | }
86 |
87 | .animate__animated.animate__delay-10s {
88 | -webkit-animation-delay: 1s;
89 | animation-delay: 1s;
90 | }
91 |
92 | .animate__animated.animate__delay-11s {
93 | -webkit-animation-delay: 1.1s;
94 | animation-delay: 1.1s;
95 | }
96 |
97 | .animate__animated.animate__delay-12s {
98 | -webkit-animation-delay: 1.2s;
99 | animation-delay: 1.2s;
100 | }
101 |
102 | .animate__animated.animate__delay-13s {
103 | -webkit-animation-delay: 1.3s;
104 | animation-delay: 1.4s;
105 | }
106 |
107 | .animate__animated.animate__delay-14s {
108 | -webkit-animation-delay: 1.5s;
109 | animation-delay: 1.5s;
110 | }
111 |
112 | .animate__animated.animate__delay-15s {
113 | -webkit-animation-delay: 1.6s;
114 | animation-delay: 1.6s;
115 | }
116 |
117 | .animate__animated.animate__delay-16s {
118 | -webkit-animation-delay: 1.7s;
119 | animation-delay: 1.7s;
120 | }
121 |
122 | .animate__animated.animate__delay-17s {
123 | -webkit-animation-delay: 1.8s;
124 | animation-delay: 1.8s;
125 | }
126 |
127 | .animate__animated.animate__delay-18s {
128 | -webkit-animation-delay: 1.9s;
129 | animation-delay: 1.9s;
130 | }
131 |
132 | .animate__animated.animate__delay-19s {
133 | -webkit-animation-delay: 2s;
134 | animation-delay: 2s;
135 | }
136 |
137 | .animate__animated.animate__delay-20s {
138 | -webkit-animation-delay: 2.1s;
139 | animation-delay: 2.1s;
140 | }
141 |
142 | #container {
143 | position: relative;
144 | left: 0;
145 | top: 0;
146 | width: 100vw;
147 | height: 100vh;
148 | }
149 |
150 | .overlay {
151 | position: absolute;
152 | top: 0;
153 | left: 0;
154 | width: 100%;
155 | height: 100%;
156 | background: rgba(0, 0, 0, .24);
157 | }
158 |
159 | .tablet__border {
160 | position: absolute;
161 | top: 50%;
162 | left: 50%;
163 | transform: translate(-50%, -50%);
164 | width: 60vw;
165 | height: 65vh;
166 | background: url("./imgs/tablet.png") no-repeat center center;
167 | background-size: 100% 100%;
168 | display: flex;
169 | align-items: center;
170 | justify-content: center;
171 | position: relative;
172 | }
173 |
174 | .tablet__container {
175 | position: relative;
176 | width: 76.2%;
177 | height: 80%;
178 | position: relative;
179 | }
180 |
181 | .tablet__wrapper {
182 | width: 100%;
183 | height: 100%;
184 | margin-top: .2vh;
185 | margin-left: -.1vw;
186 | }
187 |
188 | .__tablet {
189 | width: 100%;
190 | height: 100%;
191 | position: relative;
192 | padding: 6.5vh 2.5vw;
193 | }
194 |
195 | .tablet__wrapper#main-screen {
196 | background: url("./imgs/tablet_background2.png") center center no-repeat;
197 | background-size: 100% 100%;
198 | border-radius: 1vw;
199 | }
200 |
201 | .tablet__wrapper#job-screen {
202 | /* background: url("./imgs/tablet_job-background.png") no-repeat center center; */
203 | /* background: #1a3457; */
204 | background: #141d26;
205 | background-size: 100% 100%;
206 | position: absolute;
207 | top: 50%;
208 | left: 50%;
209 | transform: translate(-50%, -50%);
210 | border-radius: 1vw;
211 | }
212 |
213 | .tablet__header {
214 | position: absolute;
215 | top: 0;
216 | left: -.1vw;
217 | width: 100%;
218 | height: 3vh;
219 | padding: 1.8vh 1vw;
220 | display: flex;
221 | justify-content: space-between;
222 | align-items: center;
223 | background: rgba(0, 0, 0, .4);
224 | border-top-left-radius: 1.15vw;
225 | border-top-right-radius: 1.15vw;
226 | z-index: 9999;
227 | }
228 |
229 | .tablet__header--items {
230 | display: flex;
231 | align-items: center;
232 | gap: .4vw;
233 | height: 100%;
234 | }
235 |
236 | .tablet__header--items:nth-of-type(odd) {
237 | width: 25%;
238 | }
239 |
240 | .tablet__header--items:nth-of-type(2) {
241 | width: 50%;
242 | justify-content: center;
243 | }
244 |
245 | .tablet__header--items:nth-of-type(3) {
246 | justify-content: flex-end;
247 | }
248 |
249 | .tablet__header--items i, p {
250 | font-size: 1.6vh;
251 | color: var(--white-color);
252 | }
253 |
254 |
255 |
256 |
257 | .tablet__apps {
258 | position: absolute;
259 | bottom: 0;
260 | left: 50%;
261 | width: 100%;
262 | height: 7vh;
263 | transform: translate(-50%, -50%);
264 | display: flex;
265 | align-items: center;
266 | justify-content: center;
267 | gap: 1vw;
268 | }
269 |
270 | .tablet__apps .tablet__app--item {
271 | width: 5vw;
272 | height: 100%;
273 | text-align: center;
274 | cursor: pointer;
275 | }
276 |
277 | .tablet__app--item:hover .tablet__app--content {
278 | color: var(--white-color);
279 | }
280 |
281 | .tablet__app--item:hover img {
282 | transform: translateY(-.5vh);
283 | }
284 |
285 | .tablet__app--item img {
286 | height: 4.5vh;
287 | margin-bottom: -.5vh;
288 | transition: .25s ease;
289 | }
290 |
291 | .tablet__app--content {
292 | font-size: 1.5vh;
293 | font-weight: 500;
294 | color: var(--color-2);
295 | transition: .25s ease;
296 | }
297 |
298 | .tablet__info {
299 | position: absolute;
300 | top: 24.5%;
301 | left: 50%;
302 | height: 5vh;
303 | display: flex;
304 | align-items: center;
305 | justify-content: center;
306 | gap: 1.5vw;
307 | transform: translate(-50%, -50%);
308 | }
309 |
310 | .tablet__info h3 {
311 | font-weight: 400;
312 | font-size: 4.8vh;
313 | color: var(--white-color);
314 | }
315 |
316 | .tablet__info h3 span {
317 | font-size: 2vh;
318 | }
319 |
320 | .tablet__info .bars {
321 | height: 100%;
322 | width: .08vw;
323 | margin-top: .6vh;
324 | background-color: rgb(255, 255, 255);
325 | }
326 |
327 | .tablet__info--weather {
328 | display: flex;
329 | align-items: center;
330 | gap: 1vw;
331 | }
332 |
333 | .tablet__info--weather img {
334 | height: 5vh;
335 | }
336 |
337 | .tablet__weather--top {
338 | font-size: 2.6vh;
339 | margin-top: 1.36vh;
340 | margin-bottom: -1.28vh;
341 | }
342 |
343 | .tablet__weather--bottom {
344 | font-size: 1.5vh;
345 | }
346 |
347 | .logo {
348 | width: 6.5vw;
349 | height: 11vh;
350 | position: absolute;
351 | top: 50%;
352 | left: 50%;
353 | transform: translate(-50%, -50%);
354 | }
355 |
356 | .__tablet--header {
357 | position: relative;
358 | z-index: 1;
359 | width: 100%;
360 | height: 10%;
361 | display: flex;
362 | align-items: center;
363 | justify-content: space-between;
364 | }
365 |
366 | .__tablet--header--left {
367 | display: flex;
368 | align-items: center;
369 | gap: .8vw;
370 | }
371 |
372 | .__tablet--header--left i {
373 | font-size: 4vh;
374 | /* color: rgb(71, 71, 71); */
375 | color: #F5F8FA;
376 | }
377 |
378 | .__tablet--header-content {
379 | text-transform: var(--main-font-transform);
380 | font-size: 3.2vh;
381 | /* color: rgb(71, 71, 71); */
382 | color: #F5F8FA;
383 |
384 |
385 | }
386 |
387 | .__tablet--search-container {
388 | width: 12vw;
389 | height: 4vh;
390 | position: relative;
391 | }
392 |
393 | .searchbox {
394 | width: 100%;
395 | height: 100%;
396 | overflow: hidden;
397 | }
398 |
399 | .search-input {
400 | position: absolute;
401 | left: 0;
402 | width: 100%;
403 | padding-right: 2.5vw;
404 | box-sizing: border-box;
405 | height: 5vh;
406 | border: 0;
407 | font-size: 1.6vh;
408 | background: transparent;
409 | color: #F5F8FA;
410 | outline: none;
411 | }
412 |
413 | .search-input::placeholder {
414 | color: #AAB8C2;
415 | }
416 |
417 | .searchbox button {
418 | position: absolute;
419 | right: 0;
420 | top: 0;
421 | width: 1.4vw;
422 | height: 2.5vh;
423 | outline: none;
424 | }
425 |
426 | .line {
427 | position: absolute;
428 | bottom: 0;
429 | left: 0;
430 | right: 0;
431 | margin: auto;
432 | width: 100%;
433 | height: .2vh;
434 | /* background: #ffffff85; */
435 | /* background: #48cffe; */
436 | background: #657786;
437 |
438 |
439 | }
440 |
441 | .submit {
442 | -webkit-appearance: none;
443 | background: transparent;
444 | border: 0;
445 | margin-top: .3vh;
446 | }
447 |
448 | .submit::before {
449 | content: "";
450 | position: absolute;
451 | width: 60%;
452 | height: 60%;
453 | left: 10%;
454 | top: 50%;
455 | box-sizing: border-box;
456 | border: .3vh solid #ffd10d;
457 | border-radius: 50%;
458 | }
459 |
460 | .submit::after {
461 | content: "";
462 | position: absolute;
463 | width: .15vw;
464 | height: .6vh;
465 | background: #ffd10d;
466 | transform-origin: 50% 0%;
467 | transform: rotate(-45deg);
468 | top: 95%;
469 | left: 60%;
470 | }
471 |
472 | .tablet__back--mainscreen {
473 | width: 1.7vw;
474 | height: 3.1vh;
475 | cursor: pointer;
476 | border-radius: 50%;
477 | position: absolute;
478 | top: 105%;
479 | left: 49%;
480 | opacity: 0;
481 | transform: translate(-50%, -50%);
482 | z-index: 9999;
483 | }
484 |
485 | .tablet__job--list {
486 | margin-top: 3vh;
487 | width: 105%;
488 | height: 37vh;
489 | overflow-y: scroll;
490 | overflow-x: hidden;
491 | }
492 |
493 | .tablet__job--list::-webkit-scrollbar {
494 | width: .28vw;
495 | display: none;
496 | }
497 |
498 | .tablet__job--item {
499 | width: 89%;
500 | height: 100%;
501 | /* background: linear-gradient(145deg, rgba(71, 71, 71, 0.7), #828282); */
502 | /* background: #142740; */
503 | background: #243447;
504 | box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
505 | border-top-left-radius: .25vw;
506 | border-top-right-radius: .25vw;
507 | border-bottom: .2vh solid #AAB8C2;
508 | display: flex;
509 | align-items: center;
510 | box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;
511 | }
512 |
513 | #get-job {
514 | font-size: 4vh;
515 | /* color: #9e9e9e; */
516 | /* color: #ffd10d; */
517 | color: #1DA1F2;
518 | cursor: pointer;
519 | transition: .25s ease;
520 | }
521 |
522 | dfn {
523 | position: relative;
524 | }
525 |
526 | dfn::after {
527 | content: attr(data-info);
528 | border-bottom: .25vh solid gold;
529 | display: inline;
530 | position: absolute;
531 | top: 10%;
532 | left: -65%;
533 | opacity: 0;
534 | display: flex;
535 | justify-content: center;
536 | text-transform: var(--main-font-transform);
537 | align-items: center;
538 | min-width: 4vw;
539 | height: 1.5vh;
540 | font-size: 1.05vh;
541 | padding: .5vw;
542 | font-weight: 700;
543 | border-radius: .25vw;
544 | background: rgba(49, 49, 49, 0.9);
545 | color: var(--white-color);
546 | pointer-events: none;
547 | transition: opacity 250ms, top 250ms;
548 | }
549 |
550 | dfn:hover {z-index: 999999;}
551 | dfn:hover::after {opacity: 1; top: -35%;}
552 |
553 | dfn:hover #get-job {
554 | color: #243447;
555 | }
556 |
557 | .icon {
558 | font-size: 4.8vh;
559 | color: var(--white-color);
560 | }
561 |
562 | .tablet__job--item--eles:nth-of-type(1) {
563 | width: 18%;
564 | height: 100%;
565 | display: flex;
566 | justify-content: center;
567 | align-items: center;
568 | }
569 |
570 | .tablet__job--item--eles:nth-of-type(2) {
571 | width: 42%;
572 | height: 100%;
573 | }
574 |
575 | .tablet__job--item--eles:nth-of-type(3) {
576 | width: 40%;
577 | height: 100%;
578 | display: flex;
579 | justify-content: flex-start;
580 | align-items: center;
581 | }
582 |
583 | .tablet__job--content {
584 | display: flex;
585 | align-items: flex-start;
586 | flex-direction: column;
587 | }
588 |
589 | .tablet__job--content--name {
590 | text-transform: capitalize;
591 | margin-bottom: -.5vh;
592 | margin-top: 1.25vh;
593 | font-size: 2vh;
594 | font-weight:600;
595 | }
596 |
597 | .tablet__job--content--bottom {
598 | display: flex;
599 | gap: 1vw;
600 | }
601 |
602 | .bottom__content {
603 | display: flex;
604 | align-items: center;
605 | gap: .8vw;
606 | }
607 |
608 | .salary__content {
609 | text-transform: capitalize;
610 | font-weight: 600;
611 | }
612 |
613 | .high {
614 | /* color: rgb(107, 255, 38); */
615 | color:#80ED99
616 | }
617 |
618 | .medium {
619 | /* color: rgb(255, 179, 38); */
620 | color:#F77F00
621 | }
622 |
623 | .low {
624 | color: #D62828;
625 | /* color: rgb(255, 112, 112); */
626 | }
627 |
628 | .tablet__job--item-description {
629 | line-height: 2.4vh;
630 | }
--------------------------------------------------------------------------------
/esx ver/rep-tablet/Ui/ui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | REP TABLET
12 |
13 |
14 |
15 |
25 |
26 |
42 |
43 |
44 |
45 |
46 |
62 |
63 |
64 |
65 |
66 |
Settings
67 |
68 |
69 |
70 |
Google
71 |
72 |
73 |
74 |
Job Center
75 |
76 |
77 |
78 |
Facebook
79 |
80 |
81 |
82 |
Instagram
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
35° C
92 |
Ha Noi, Viet Nam
93 |
94 |
95 |
96 |
97 |
98 |
117 |
118 |
119 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
160 |
161 |
162 |
171 |
172 |
173 |
178 |
179 |
180 |
181 |
182 |
183 |
186 |
189 |
192 |
195 |
198 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
Please Wait...
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/client/cl_group.lua:
--------------------------------------------------------------------------------
1 | local inJob = false
2 | local requestCoolDown = false
3 | local isGroupLeader = false
4 | local vpn = false
5 | local groupID = 0
6 | local JobCenter = {}
7 | local request = false
8 |
9 | local function loadConfig()
10 | SendNUIMessage({
11 | action = "loadConfig",
12 | config = Config.JobCenter,
13 | })
14 | end
15 |
16 | exports("IsGroupLeader", function()
17 | return isGroupLeader
18 | end)
19 |
20 | exports("GetGroupID", function()
21 | return groupID
22 | end)
23 |
24 | local function ReQuest(title, text, icon, color, timeout, accept, deny)
25 | request = promise.new()
26 | SendNUIMessage({
27 | action = "ReQuest",
28 | TabletNotify = {
29 | title = title or "Rep Scripts",
30 | text = text or "MSG",
31 | icon = icon or "fas fa-home",
32 | color = color or "#FFBF00",
33 | timeout = timeout or 7500, -- Nếu là "NONE" thì sẽ không tự tắt
34 | accept = accept or "fas fa-check-circle",
35 | deny = deny or "fas fa-times-circle",
36 | },
37 | })
38 | local result = Citizen.Await(request)
39 | return result
40 | end
41 |
42 | RegisterNUICallback('AcceptNotification', function()
43 | request:resolve(true)
44 | request = nil
45 | end)
46 |
47 | RegisterNUICallback('DenyNotification', function()
48 | request:resolve(false)
49 | request = nil
50 | end)
51 |
52 | exports("ReQuest", ReQuest)
53 |
54 | -- Khi bật App sẽ gửi về để xem có job hay không, nếu có job thì kiểm tra
55 | RegisterNUICallback('GetData', function(data, cb)
56 | local job = LocalPlayer.state.nghe
57 | if job then
58 | ESX.TriggerServerCallback('rep-tablet:callback:getGroupsApp', function (bool, data)
59 | if bool then
60 | SendNUIMessage({
61 | action = "addGroupStage", -- Khi set State thì status về true, còn refresh App thì status của job về false. Nếu Stage == {} thì đưa về giao diện các thành viên trong nhóm
62 | status = data, -- cấu trúc của stage https://cdn.discordapp.com/attachments/1036820124784668692/1052217816528461894/image.png
63 | })
64 | else
65 | SendNUIMessage({
66 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
67 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận // Thông tin các nhóm
68 | job = LocalPlayer.state.nghe -- Nghề, lọc ra các nhóm trong bảng data có cùng nghề
69 | })
70 | end
71 | end)
72 | else --- jobcenter thì sẽ hiện danh sách các nghề
73 | SendNUIMessage({
74 | action = "jobcenter",
75 | data = JobCenter,
76 | })
77 | end
78 | end)
79 |
80 | -- Tạo blip đến chỗ làm việc
81 | RegisterNUICallback('CreateBlip', function(data)
82 | TriggerEvent(data.event)
83 | end)
84 |
85 | RegisterNUICallback('readyToJob', function()
86 | if groupID == 0 then return end
87 | local success = ReQuest("Job Offer", 'Would you like to begin this job?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
88 | if success == nil then return end
89 | if success then
90 | TriggerEvent('rep-tablet:client:readyforjob')
91 | else
92 | SendNUIMessage({
93 | action = "reLoop", -- Khi set State thì status về true, còn refresh App thì status của job về fail
94 | })
95 | end
96 | end)
97 |
98 | -- Tạo nhóm
99 | RegisterNUICallback('CreateJobGroup', function(data, cb) --employment
100 | local result = vpn
101 | TriggerServerEvent('rep-tablet:server:createJobGroup', result, LocalPlayer.state.nghe)
102 | isGroupLeader = true
103 | cb("ok")
104 | end)
105 |
106 | --Xin vào nhóm
107 | RegisterNUICallback('RequestToJoin', function (data, cb)
108 | if not requestCoolDown then
109 | requestCoolDown = true
110 | ESX.ShowNotification("Sent Request", "success")
111 | TriggerServerEvent('rep-tablet:server:requestJoinGroup', data)
112 | Wait(5000)
113 | requestCoolDown = false
114 | else
115 | ESX.ShowNotification("You need to wait before requesting again", "error")
116 | end
117 | end)
118 |
119 | RegisterNUICallback('checkOut', function (data, cb)
120 | if groupID ~= 0 or inJob then
121 | if inJob then
122 | SendNUIMessage({
123 | action = "closeAllNotification",
124 | })
125 | TriggerServerEvent('rep-tablet:server:checkout', groupID)
126 | LocalPlayer.state:set('nghe', nil, false)
127 | end
128 | end
129 | if groupID == 0 then
130 | TriggerEvent('rep-tablet:client:checkout')
131 | end
132 | SendNUIMessage({
133 | action = "jobcenter",
134 | data = JobCenter,
135 | })
136 | end)
137 |
138 | RegisterNetEvent('rep-tablet:client:closeAllNotification', function ()
139 | SendNUIMessage({
140 | action = "closeAllNotification",
141 | })
142 | end)
143 | -- Out khỏi nhóm
144 | RegisterNUICallback('LeaveGroup', function(data, cb) --data của nhóm ấn vào
145 | if not data then return end
146 | local success = ReQuest("Job Center", 'Are you sure you want to leave the group?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
147 | if success then
148 | isGroupLeader = false
149 | TriggerServerEvent('rep-tablet:server:LeaveGroup', groupID)
150 | cb("ok")
151 | end
152 | end)
153 |
154 | RegisterNUICallback('DisbandGroup', function(data, cb) --data của nhóm ấn vào
155 | if not data then return end
156 | local success = ReQuest("Job Center", 'Are you sure you want to disband the group?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
157 | if success then
158 | isGroupLeader = false
159 | TriggerServerEvent('rep-tablet:server:DisbandGroup', groupID)
160 | cb("ok")
161 | end
162 | end)
163 | -- Event
164 |
165 | -- Làm mới nhóm, ai đang trong stage sẽ không sửa lại
166 | RegisterNetEvent('rep-tablet:client:RefreshGroupsApp', function(bool)
167 | local job = LocalPlayer.state.nghe
168 | if not job then
169 | SendNUIMessage({
170 | action = "jobcenter",
171 | data = JobCenter,
172 | })
173 | else
174 | if bool then inJob = false end
175 | if inJob then return end
176 | ESX.TriggerServerCallback('rep-tablet:callback:getGroupsApp', function (bool1, data)
177 | if bool1 then
178 | SendNUIMessage({
179 | action = "addGroupStage", -- Khi set State thì status về true, còn refresh App thì status của job về false. Nếu Stage == {} thì đưa về giao diện các thành viên trong nhóm
180 | status = data, -- cấu trúc của stage https://cdn.discordapp.com/attachments/1036820124784668692/1052217816528461894/image.png
181 | })
182 | else
183 | SendNUIMessage({
184 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
185 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận // Thông tin các nhóm
186 | job = LocalPlayer.state.nghe -- Nghề, lọc ra các nhóm trong bảng data có cùng nghề
187 | })
188 | end
189 | end)
190 | end
191 | end)
192 |
193 | -- Khi mà sign in thì sẽ hiện các ra các nhóm của nghề đó
194 | RegisterNetEvent('rep-tablet:client:signIn', function(bool)
195 | LocalPlayer.state:set('nghe', bool, false)
196 | ESX.TriggerServerCallback('rep-tablet:callback:getGroupsApp', function (bool, data)
197 | if bool then
198 | else
199 | SendNUIMessage({
200 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
201 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận
202 | job = LocalPlayer.state.nghe
203 | })
204 | end
205 | end)
206 | end)
207 |
208 | -- Khi mà sign off thì sẽ chuyển lại giao diện jobcenter
209 | RegisterNetEvent('rep-tablet:client:signOff', function()
210 | if groupID ~= 0 or inJob then
211 | if inJob then
212 | SendNUIMessage({
213 | action = "closeAllNotification",
214 | })
215 | end
216 | TriggerServerEvent('rep-tablet:server:checkout', groupID)
217 | LocalPlayer.state:set('nghe', nil, false)
218 | end
219 | if groupID == 0 then
220 | TriggerEvent('rep-tablet:client:checkout')
221 | end
222 | SendNUIMessage({
223 | action = "jobcenter",
224 | data = JobCenter,
225 | })
226 | end)
227 |
228 | -- Add nhiệm vụ
229 | RegisterNetEvent('rep-tablet:client:AddGroupStage', function(data)
230 | inJob = true
231 | SendNUIMessage({
232 | action = "addGroupStage",
233 | status = data
234 | })
235 | end)
236 |
237 | --Set Id cho group
238 | RegisterNetEvent('rep-tablet:client:UpdateGroupId', function(id)
239 | groupID = id
240 | if id == 0 then
241 | isGroupLeader = false
242 | end
243 | end)
244 |
245 | --Xin vào nhóm// Request to join a group
246 | RegisterNetEvent('rep-tablet:client:requestJoinGroup', function(target)
247 | local success = ReQuest("Job Center", target..' want to join your group', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
248 | if success then
249 | TriggerServerEvent('rep-tablet:client:requestJoin', target, true)
250 | else
251 | TriggerServerEvent('rep-tablet:client:requestJoin', target, false)
252 | end
253 | end)
254 |
255 | RegisterNetEvent('rep-tablet:client:notReady', function ()
256 | SendNUIMessage({
257 | action = "cancelReady",
258 | })
259 | end)
260 |
261 | --Update Group Job
262 | RegisterNetEvent('rep-tablet:client:updateGroupJob', function (data)
263 | Config.JobCenter = data
264 | loadConfig()
265 | JobCenter = {}
266 | for k, v in pairs(Config.JobCenter) do
267 | if vpn then
268 | JobCenter[#JobCenter+1] = v
269 | else
270 | if v.vpn == false then
271 | JobCenter[#JobCenter+1] = v
272 | end
273 | end
274 | end
275 | end)
276 |
277 | --Vào nhóm
278 | RegisterNetEvent('rep-tablet:client:Join', function(id)
279 | groupID = id
280 | TriggerServerEvent('rep-tablet:server:Join', id, vpn)
281 | end)
282 |
283 | -- ReQuest
284 | RegisterNetEvent("rep-tablet:client:request", function(title, text, icon, color, timeout, accept, deny)
285 | ReQuest(title, text, icon, color, timeout, accept, deny)
286 | end)
287 |
288 | RegisterNetEvent('rep-tablet:jobcenter:tow', function()
289 | SetNewWaypoint(-238.94, -1183.74)
290 | end)
291 |
292 | RegisterNetEvent('rep-tablet:jobcenter:taxi', function()
293 | SetNewWaypoint(909.51, -177.36)
294 | end)
295 |
296 | RegisterNetEvent('rep-tablet:jobcenter:postop', function()
297 | SetNewWaypoint(-432.51, -2787.98)
298 | end)
299 |
300 | RegisterNetEvent('rep-tablet:jobcenter:sanitation', function()
301 | SetNewWaypoint(-351.44, -1566.37)
302 | end)
303 |
304 | local function CheckVPN()
305 | for _, itemData in pairs(ESX.PlayerData.inventory) do
306 | if itemData.name == 'vpn' then
307 | return true
308 | end
309 | end
310 | return false
311 | end
312 |
313 | RegisterNetEvent('esx:removeInventoryItem', function(item, count)
314 | local result = CheckVPN()
315 | if vpn ~= result then
316 | vpn = result
317 | JobCenter = {}
318 | for k, v in pairs(Config.JobCenter) do
319 | if vpn then
320 | JobCenter[#JobCenter+1] = v
321 | else
322 | if v.vpn == false then
323 | JobCenter[#JobCenter+1] = v
324 | end
325 | end
326 | end
327 | TriggerServerEvent('rep-tablet:server:updateVPN', result)
328 | end
329 | end)
330 |
331 | RegisterNetEvent('esx:addInventoryItem', function(item)
332 | local result = CheckVPN()
333 | if vpn ~= result then
334 | vpn = result
335 | JobCenter = {}
336 | for k, v in pairs(Config.JobCenter) do
337 | if vpn then
338 | JobCenter[#JobCenter+1] = v
339 | else
340 | if v.vpn == false then
341 | JobCenter[#JobCenter+1] = v
342 | end
343 | end
344 | end
345 | TriggerServerEvent('rep-tablet:server:updateVPN', result)
346 | end
347 | end)
348 |
349 | -- Handles state if resource is restarted live.
350 | AddEventHandler('onResourceStart', function(resource)
351 | if GetCurrentResourceName() == resource then
352 | vpn = CheckVPN()
353 | JobCenter = {}
354 | for k, v in pairs(Config.JobCenter) do
355 | if vpn then
356 | JobCenter[#JobCenter+1] = v
357 | else
358 | if v.vpn == false then
359 | JobCenter[#JobCenter+1] = v
360 | end
361 | end
362 | end
363 | LocalPlayer.state.nghe = nil
364 | end
365 | end)
366 |
367 | AddEventHandler('esx:onPlayerSpawn', function(spawn)
368 | ESX.TriggerServerCallback('rep-tablet:callback:getGroupsJob', function (data)
369 | Config.JobCenter = data
370 | end)
371 | vpn = CheckVPN()
372 | loadConfig()
373 | JobCenter = {}
374 | for k, v in pairs(Config.JobCenter) do
375 | if vpn then
376 | JobCenter[#JobCenter+1] = v
377 | else
378 | if v.vpn == false then
379 | JobCenter[#JobCenter+1] = v
380 | end
381 | end
382 | end
383 | end)
384 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/client/cl_main.lua:
--------------------------------------------------------------------------------
1 | local tabletProp = 0
2 | local tabletModel = joaat("prop_cs_tablet")
3 | local isOpen = false
4 | local isDead = false
5 |
6 | local function LoadAnimation(dict)
7 | RequestAnimDict(dict)
8 | while not HasAnimDictLoaded(dict) do
9 | Wait(1)
10 | end
11 | end
12 |
13 | local function deleteTablet()
14 | if tabletProp then
15 | DeleteObject(tabletProp)
16 | tabletProp = 0
17 | end
18 | end
19 |
20 | local function LoopAnim()
21 | CreateThread(function()
22 | local ped = PlayerPedId()
23 | while isOpen do
24 | if not IsEntityPlayingAnim(ped, 'amb@code_human_in_bus_passenger_idles@female@tablet@base', 'base', 3) then
25 | LoadAnimation('amb@code_human_in_bus_passenger_idles@female@tablet@base')
26 | TaskPlayAnim(ped, 'amb@code_human_in_bus_passenger_idles@female@tablet@base', 'base', 8.0, 8.0, -1, 50, 0, false, false, false)
27 | end
28 | Wait(1)
29 | end
30 | ClearPedTasks(ped)
31 | end)
32 | end
33 |
34 | local function Anim()
35 | deleteTablet()
36 | RequestModel(tabletModel)
37 | while not HasModelLoaded(tabletModel) do
38 | Wait(1)
39 | end
40 | local ped = PlayerPedId()
41 | local pos = GetEntityCoords(ped)
42 | tabletProp = CreateObject(tabletModel, pos.x, pos.y, pos.z, 1, 1, 0)
43 | AttachEntityToEntity(tabletProp, ped, GetPedBoneIndex(ped, 60309), 0.03, 0.002, -0.05, 10.0, 160.0, 0.0, 1, 1, 0, 1, 0, 1)
44 | SetModelAsNoLongerNeeded(tabletProp)
45 | SetEntityCompletelyDisableCollision(tabletProp, false, true)
46 | LoopAnim()
47 | end
48 |
49 | local function hasTablet()
50 | for _, v in pairs(ESX.PlayerData.inventory) do
51 | if v.name == 'tablet' then
52 | return true
53 | end
54 | end
55 | end
56 | exports('hasTablet', hasTablet)
57 |
58 | RegisterNUICallback('HasTablet', function(_, cb)
59 | cb(hasTablet())
60 | end)
61 |
62 | local function CustomNotification(title, text, icon, color, timeout)
63 | SendNUIMessage({
64 | action = "CustomNotification",
65 | TabletNotify = {
66 | title = title or "Rep Scripts",
67 | text = text or "MSG",
68 | icon = icon or "fas fa-home",
69 | color = color or "#FFBF00",
70 | timeout = timeout or 1500,
71 | },
72 | })
73 | end
74 |
75 | exports("CustomNotification", CustomNotification)
76 | ---------NUI----------
77 | ---Bật Tablet
78 | local function OpenTablet()
79 | if hasTablet() then
80 | SetNuiFocus(true, true)
81 | SendNUIMessage({
82 | action = "open",
83 | data = ESX.PlayerData,
84 | name = ESX.PlayerData.firstName.." "..ESX.PlayerData.lastName,
85 | })
86 | isOpen = true
87 | Anim()
88 | else
89 | ESX.ShowNotification("You don't have a tablet?")
90 | end
91 | end
92 |
93 | --Command
94 |
95 | RegisterCommand('tablet', function()
96 | if not isOpen then
97 | if not isDead and not IsPauseMenuActive() then
98 | OpenTablet()
99 | else
100 | ESX.ShowNotification("Action not available at the moment..")
101 | end
102 | end
103 | end)
104 |
105 | RegisterKeyMapping('tablet', 'Open Tablet', 'keyboard', 'K')
106 |
107 | ---Nui-----
108 | RegisterNUICallback('Close', function()
109 | SetNuiFocus(false, false)
110 | isOpen = false
111 | deleteTablet()
112 | end)
113 |
114 | -- Send a PhoneNotification to the tablet from anywhere
115 | RegisterNetEvent("rep-tablet:client:CustomNotification", function(title, text, icon, color, timeout)
116 | CustomNotification(title, text, icon, color, timeout)
117 | end)
118 |
119 | AddEventHandler('esx:onPlayerDeath', function() isDead = true end)
120 |
121 | AddEventHandler('esx:onPlayerSpawn', function(spawn) isDead = false end)
122 |
123 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/config.lua:
--------------------------------------------------------------------------------
1 | Config = {}
2 | -- Config thêm job và event chỉ đường vào đây, vpn = true sẽ yêu cầu VPN để hiển thị
3 | Config.JobCenter = {
4 | ['towing'] = {
5 | vpn = false,
6 | label = "Towing",
7 | event = "rep-tablet:jobcenter:tow",
8 | mem = 1, -- Số lượng người tối đa trong 1 nhóm
9 | count = 0, -- Don't touch
10 | salary = 'high',
11 | time = {
12 | first = 2500,
13 | second = 10000,
14 | },
15 | icon = "fas fa-car-crash"
16 |
17 | },
18 | ['taxi'] = {
19 | vpn = false,
20 | label = "Taxi",
21 | event = "rep-tablet:jobcenter:taxi",
22 | mem = 1,
23 | count = 0,
24 | salary = 'mid',
25 | time = {
26 | first = 2500,
27 | second = 10000,
28 | },
29 | icon = "fa-solid fa-taxi"
30 | },
31 | ['chopshop'] = {
32 | vpn = true,
33 | label = "House Robbery",
34 | event = "sn-houserobbery:client:chiduong",
35 | mem = 6,
36 | count = 0,
37 | salary = 'mid',
38 | time = {
39 | first = 2500,
40 | second = 10000,
41 | },
42 | icon = "fa-solid fa-mask"
43 | },
44 | ['oxyrun'] = {
45 | vpn = true,
46 | label = "Oxy Run",
47 | event = "rep-oxyrun:client:chiduong",
48 | mem = 1,
49 | count = 0,
50 | salary = 'mid',
51 | time = {
52 | first = 2500,
53 | second = 10000,
54 | },
55 | icon = "fa-solid fa-pills"
56 | },
57 | ['theftcar'] = {
58 | vpn = true,
59 | label = "Chop Shop",
60 | event = "rep-chopshop:client:chiduong",
61 | mem = 1,
62 | count = 0,
63 | salary = 'mid',
64 | time = {
65 | first = 2500,
66 | second = 10000,
67 | },
68 | icon = "fas fa-lock-open"
69 | },
70 | ['postop'] = {
71 | vpn = false,
72 | label = "PostOp Worker",
73 | event = "rep-tablet:jobcenter:postop",
74 | mem = 2,
75 | count = 0,
76 | salary = 'mid',
77 | time = {
78 | first = 2500,
79 | second = 10000,
80 | },
81 | icon = "fa-solid fa-truck-fast"
82 | },
83 | ['sani'] = {
84 | vpn = false,
85 | label = "Sanitation Worker",
86 | event = "rep-tablet:jobcenter:sanitation",
87 | mem = 4,
88 | count = 0,
89 | salary = 'low',
90 | time = {
91 | first = 2500,
92 | second = 10000,
93 | },
94 | icon = "fas fa-trash"
95 | },
96 | ['taco'] = {
97 | vpn = true,
98 | label = "Taco Shop",
99 | event = "rep-weed:client:chiduong",
100 | mem = 1,
101 | count = 0,
102 | salary = 'mid',
103 | time = {
104 | first = 2500,
105 | second = 10000,
106 | },
107 | icon = "fas fa-cannabis"
108 | },
109 | }
110 |
111 | -- Họ sẽ được random khi trong người có VPN
112 | Config.FirstName = {
113 | 'Trump',
114 | 'Musk',
115 | 'Adams',
116 | 'Harrison',
117 | 'Taft',
118 | 'Long',
119 | 'Lodge',
120 | 'Kennedy',
121 | 'Bayh',
122 | 'Indiana',
123 | 'Brown',
124 | 'Miller',
125 | 'Davis',
126 | 'Garcia',
127 | }
128 | -- Tên sẽ được random khi trong người có VPN
129 | Config.LastName = {
130 | 'James',
131 | 'Robert',
132 | 'John',
133 | 'Michael',
134 | 'Cheng',
135 | 'BahnMy',
136 | 'Cris',
137 | 'Hwan',
138 | 'William'
139 | }
--------------------------------------------------------------------------------
/esx ver/rep-tablet/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 | game 'gta5'
3 |
4 | name "Rep Dev - Tablet"
5 | author "Q4D#1905 x HWANJR#0928"
6 | version "1.1.2"
7 |
8 | client_scripts {'client/*.lua'}
9 | server_scripts {'server/*.lua'}
10 |
11 | ui_page 'Ui/ui.html'
12 | files {
13 | 'Ui/ui.html',
14 | 'Ui/*.css',
15 | 'Ui/*.js',
16 | 'Ui/imgs/*.png',
17 | 'Ui/imgs/app/*.png',
18 | 'Ui/sounds/*.ogg'
19 | }
20 |
21 | shared_scripts {
22 | '@es_extended/imports.lua',
23 | 'config.lua'
24 | }
25 | lua54 'yes'
26 |
--------------------------------------------------------------------------------
/esx ver/rep-tablet/server/sv_group.lua:
--------------------------------------------------------------------------------
1 | local Players = {} -- Don't Touch if you don't know
2 | local Groups = {}
3 | -- Lấy tên của người chơi
4 | local function GetPlayerCharName(src)
5 | local xPlayer = ESX.GetPlayerFromId(src)
6 | return xPlayer.getName()
7 | end
8 |
9 | -- Random Name khi có VPN
10 | local function RandomName()
11 | local random1 = math.random(1, #Config.FirstName)
12 | local random2 = math.random(1, #Config.LastName)
13 | return Config.FirstName[random1].." "..Config.LastName[random2]
14 | end
15 |
16 | -- Gửi thông báo cho tất cả thành viên trong nhóm // Thay đổi loại thông báo tuỳ server
17 | local function NotifyGroup(group, msg, type, time)
18 | if not group or not Groups[group] then return print("Group not found...") end
19 | for _, v in pairs(Groups[group].members) do
20 | local xPlayer = ESX.GetPlayerFromId(v.player)
21 | xPlayer.showNotification(msg or "NO MSG")
22 | end
23 | end
24 |
25 | exports("NotifyGroup", NotifyGroup)
26 |
27 | -- Gửi thông báo Custom của điện thoại cho tất cả thành viên trong nhóm
28 | local function pNotifyGroup(group, header, msg, icon, colour, length)
29 | if not group or not Groups[group] then return print("Group not found...") end
30 | for _, v in pairs(Groups[group].members) do
31 | TriggerClientEvent('rep-tablet:client:CustomNotification', v.player,
32 | header or "NO HEADER",
33 | msg or "NO MSG",
34 | icon or "fas fa-phone-square",
35 | colour or "#e84118",
36 | length or 7500
37 | )
38 | end
39 | end
40 |
41 | exports("pNotifyGroup", pNotifyGroup)
42 |
43 | --Lấy Group bằng members
44 | local function getGroup(src)
45 | if not Players[src] then return nil end
46 | for group, _ in pairs(Groups) do
47 | for _, v in pairs (Groups[group].members) do
48 | if v.player == src then
49 | return Groups[group]
50 | end
51 | end
52 | end
53 | return nil
54 | end
55 |
56 | exports("getGroup", getGroup)
57 |
58 | --Lấy Id của group bằng members
59 | local function getGroupByMembers(src)
60 | if not Players[src] then return nil end
61 | for group, _ in pairs(Groups) do
62 | for _, v in pairs (Groups[group].members) do
63 | if v.player == src then
64 | return group
65 | end
66 | end
67 | end
68 | return nil
69 | end
70 |
71 | exports("getGroupByMembers", getGroupByMembers)
72 |
73 | -- Lấy id của các member trong group bằng id của group
74 | local function getGroupMembers(id)
75 | if not id then return print("Id not found") end
76 | if not Groups[id] then return print("Group :"..id.." not found") end
77 | local temp = {}
78 | for _,v in pairs(Groups[id].members) do
79 | temp[#temp+1] = v.player
80 | end
81 | return temp
82 | end
83 |
84 | exports('getGroupMembers', getGroupMembers)
85 |
86 | -- Lấy số lượng thành viên trong nhóm
87 | local function getGroupSize(id)
88 | if not id then return print("Id not found") end
89 | if not Groups[id] then return print("Group :"..id.." not found") end
90 | return Groups[id].users
91 | end
92 |
93 | exports('getGroupSize', getGroupSize)
94 |
95 | -- Lấy id của trường nhóm bằng id của nhóm
96 | local function GetGroupLeader(id)
97 | if not id then return print("Id not found") end
98 | if Groups[id] == nil then
99 | return
100 | end
101 | return Groups[id].leader
102 | end
103 |
104 | exports("GetGroupLeader", GetGroupLeader)
105 |
106 | -- Trigger event cho các thành viên trong group
107 | function GroupEvent(id, event, args)
108 | if not id then return print("Id not found") end
109 | if not Groups[id] then return print("Group :"..id.." not found") end
110 | if not event then return print("no valid event was passed to GroupEvent") end
111 | local members = getGroupMembers(id)
112 | if members and #members > 0 then
113 | for i = 1, #members do
114 | if members[i] then
115 | if args ~= nil then
116 | TriggerClientEvent(event, members[i], table.unpack(args))
117 | else
118 | TriggerClientEvent(event, members[i])
119 | end
120 | end
121 | end
122 | end
123 | end
124 |
125 | exports("GroupEvent", GroupEvent)
126 |
127 | -- Kiểm tra xem có phải trưởng nhóm hay không
128 | local function isGroupLeader(src, id)
129 | if not id then return end
130 | local grouplead = GetGroupLeader(id)
131 | return grouplead == src or false
132 | end
133 |
134 | exports('isGroupLeader', isGroupLeader)
135 |
136 | ---- Set nhiệm vụ cho nhóm
137 | local function setJobStatus(id, stages)
138 | if not id then return print("Id not found") end
139 | if not Groups[id] then return print("Group :"..id.." not found") end
140 | Groups[id].status = true
141 | Groups[id].stage = stages or {}
142 | local m = getGroupMembers(id)
143 | if not m then return end
144 | for i=1, #m do
145 | if m[i] then
146 | TriggerClientEvent("rep-tablet:client:AddGroupStage", m[i], Groups[id])
147 | end
148 | end
149 | end
150 | exports('setJobStatus', setJobStatus)
151 |
152 | -- Đổi trưởng nhóm
153 | local function ChangeGroupLeader(id)
154 | if not id then return print("Id not found") end
155 | if not Groups[id] then return print("Group :"..id.." not found") end
156 | local members = Groups[id].members
157 | local leader = GetGroupLeader(id)
158 | if #members > 1 then
159 | for i=1, #members do
160 | if members[i].player ~= leader then
161 | Groups[id].leader = members[i].player
162 | Groups[id].gName = members[i].name
163 | local xPlayer = ESX.GetPlayerFromId(members[i].player)
164 | xPlayer.showNotification("You have become the group leader")
165 | return true
166 | end
167 | end
168 | end
169 | return false
170 | end
171 |
172 | -- Reset Stage của nhóm về không
173 | local function resetJobStatus(id)
174 | if not id then return print("Id not found") end
175 | if not Groups[id] then return print("Group :"..id.." not found") end
176 | Groups[id].status = false
177 | Groups[id].stage = {}
178 | local m = getGroupMembers(id)
179 | if not m then return end
180 | for i=1, #m do
181 | if m[i] then
182 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
183 | end
184 | end
185 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
186 | end
187 |
188 | exports('resetJobStatus', resetJobStatus)
189 |
190 | -- Xoá nhóm
191 | local function DestroyGroup(id)
192 | if not id then return print("Id not found") end
193 | if not Groups[id] then return print("Group :"..id.." not found") end
194 | local members = getGroupMembers(id)
195 | if members and #members > 0 then
196 | for i = 1, #members do
197 | if members[i] then
198 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', members[i], 0)
199 | TriggerClientEvent('rep-tablet:client:checkout', members[i])
200 | TriggerClientEvent('rep-tablet:client:closeAllNotification', members[i])
201 | Wait(100)
202 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', members[i], true)
203 | Players[members[i]] = false
204 | end
205 | end
206 | end
207 | if Config.JobCenter[Groups[id].job] then
208 | Config.JobCenter[Groups[id].job].count = Config.JobCenter[Groups[id].job].count - 1
209 | end
210 | TriggerClientEvent('rep-tablet:client:updateGroupJob', -1, Config.JobCenter)
211 | Groups[id] =
212 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
213 | end
214 |
215 | exports("DestroyGroup", DestroyGroup)
216 |
217 | -- Đuổi người chơi khỏi nhóm
218 | local function RemovePlayerFromGroup(src, id, disconnected)
219 | if not Players[src] then return false end
220 | if not id then return print("Id not found") end
221 | if not Groups[id] then return print("Group :"..id.." not found") end
222 | local g = Groups[id].members
223 | for k,v in pairs(g) do
224 | if v.player == src then
225 | table.remove(Groups[id].members, k)
226 | Groups[id].users = Groups[id].users - 1
227 | Players[src] = false
228 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', src, 0)
229 | pNotifyGroup(id, "Job Center", src.." has left the group", "fas fa-users", "#FFBF00", 7500)
230 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', src,true)
231 | local xPlayer = ESX.GetPlayerFromId(src)
232 | if disconnected then
233 | xPlayer.showNotification("You have left the group")
234 | TriggerClientEvent('rep-tablet:client:checkout', src)
235 | else
236 | xPlayer.showNotification("You have left the group")
237 | end
238 | if Groups[id].users <= 0 then
239 | DestroyGroup(id)
240 | else
241 | local m = getGroupMembers(id)
242 | if not m then return end
243 | for i=1, #m do
244 | if m[i] then
245 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
246 | end
247 | end
248 | end
249 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
250 | return
251 | end
252 | end
253 | end
254 |
255 | ----EVENT-----
256 | --Tạo nhóm
257 | RegisterNetEvent("rep-tablet:server:createJobGroup", function(bool, job)
258 | local src = source
259 | local xPlayer = ESX.GetPlayerFromId(src)
260 | if Players[src] then xPlayer.showNotification("You have already created a group") return end
261 | Players[src] = true
262 | local ID = #Groups+1
263 | local name
264 | if bool then
265 | name = RandomName()
266 | else
267 | name = GetPlayerCharName(src)
268 | end
269 | Groups[ID] = {
270 | id = ID,
271 | status = false,
272 | job = job,
273 | gName = name,
274 | users = 1,
275 | leader = src,
276 | members = {
277 | {name = name, cid = xPlayer.identifier, player = src, vpn = bool}
278 | },
279 | stage = {},
280 | }
281 | if Config.JobCenter[job] then
282 | Config.JobCenter[job].count = Config.JobCenter[job].count + 1
283 | else
284 | Config.JobCenter[job].count = 1
285 | end
286 | TriggerClientEvent('rep-tablet:client:updateGroupJob', -1, Config.JobCenter)
287 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1, Groups)
288 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', src, ID)
289 | TriggerClientEvent('rep-tablet:client:AddGroupStage', src, Groups[ID])
290 | end)
291 |
292 | RegisterNetEvent("rep-tablet:server:updateVPN", function (result)
293 | local src = source
294 | if Players[src] then
295 | local id = getGroupByMembers(src)
296 | local leader = isGroupLeader(src, id)
297 | if result then
298 | local name = RandomName()
299 | if leader then
300 | Groups[id].gName = name
301 | end
302 | for _, v in pairs (Groups[id].members) do
303 | if v.player == src then
304 | Groups[id].members[_].name = name
305 | Groups[id].members[_].vpn = true
306 | end
307 | end
308 | else
309 | local name = GetPlayerCharName(src)
310 | if leader then
311 | Groups[id].gName = name
312 | end
313 | for _, v in pairs (Groups[id].members) do
314 | if v.player == src then
315 | Groups[id].members[_].name = name
316 | Groups[id].members[_].vpn = false
317 | end
318 | end
319 | end
320 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
321 | local m = getGroupMembers(id)
322 | if not m then return end
323 | for i=1, #m do
324 | if m[i] then
325 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
326 | end
327 | end
328 | end
329 | end)
330 |
331 | RegisterNetEvent('rep-tablet:server:requestJoinGroup', function(data)
332 | local src = source
333 | local xPlayer = ESX.GetPlayerFromId(src)
334 | if Players[src] then return xPlayer.showNotification("You are already a part of a group") end
335 | if not data.id then
336 | return
337 | end
338 | if not Groups[data.id] then return xPlayer.showNotification("That group doesn't exist") end
339 | local leader = GetGroupLeader(data.id)
340 | TriggerClientEvent('rep-tablet:client:requestJoinGroup', leader, src)
341 | end)
342 |
343 | RegisterNetEvent('rep-tablet:client:requestJoin', function(target, bool)
344 | local src = source
345 | local xPlayer = ESX.GetPlayerFromId(src)
346 | local targetPlayer = ESX.GetPlayerFromId(target)
347 | if not Groups[getGroupByMembers(src)] then return xPlayer.showNotification("That group doesn't exist") end
348 | if Groups[getGroupByMembers(src)].status == true then
349 | xPlayer.showNotification("This group is already working!")
350 | return
351 | end
352 | if bool then
353 | if getGroupSize(getGroupByMembers(src)) < 6 then
354 | TriggerClientEvent('rep-tablet:client:Join', target, getGroupByMembers(src))
355 | else
356 | targetPlayer.showNotification(getGroupByMembers(src).." is full")
357 | xPlayer.showNotification("Cannot recruit more people into the team")
358 | end
359 | else
360 | targetPlayer.showNotification("The group leader "..getGroupByMembers(src).." has rejected you")
361 | end
362 | end)
363 |
364 | RegisterNetEvent('rep-tablet:server:Join', function (id, vpn)
365 | local src = source
366 | local xPlayer = ESX.GetPlayerFromId(src)
367 | if Players[src] then return xPlayer.showNotification("You are already a part of a group!") end
368 | if not id then
369 | return
370 | end
371 | if not Groups[id] then return xPlayer.showNotification("That group doesn't exist") end
372 | if Groups[id].status == true then
373 | xPlayer.showNotification("This group is already working!")
374 | return
375 | end
376 | local name
377 | if vpn then
378 | name = RandomName()
379 | else
380 | name = GetPlayerCharName(src)
381 | end
382 | pNotifyGroup(id, "Job Center", src.." has join the group", "fas fa-users", "#FFBF00", 7500)
383 | Groups[id].members[#Groups[id].members+1] = {name = name, cid = xPlayer.identifier, player = src, vpn = vpn}
384 | Groups[id].users = Groups[id].users + 1
385 | Players[src] = true
386 | local m = getGroupMembers(id)
387 | if not m then return end
388 | for i=1, #m do
389 | if m[i] then
390 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
391 | end
392 | end
393 | xPlayer.showNotification("You joined the group "..id)
394 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1, Groups)
395 | TriggerClientEvent('rep-tablet:client:JoinSuccess',src)
396 | end)
397 |
398 | RegisterNetEvent('rep-tablet:server:LeaveGroup', function(id)
399 | local src = source
400 | if not id then
401 | return
402 | end
403 | if not Players[src] then return end
404 | if isGroupLeader(src, id) then
405 | local change = ChangeGroupLeader(id)
406 | if change then
407 | RemovePlayerFromGroup(src, id)
408 | else
409 | DestroyGroup(id)
410 | end
411 | else
412 | RemovePlayerFromGroup(src, id)
413 | end
414 | end)
415 |
416 | RegisterNetEvent('rep-tablet:server:DisbandGroup', function(id)
417 | local src = source
418 | if not Players[src] then return end
419 | DestroyGroup(id)
420 | end)
421 |
422 | RegisterNetEvent('rep-tablet:server:checkout', function(id)
423 | local src = source
424 | if not Players[src] then return end
425 | if isGroupLeader(src, id) then
426 | if Groups[id].status == true then
427 | DestroyGroup(id)
428 | else
429 | local change = ChangeGroupLeader(id)
430 | if change then
431 | RemovePlayerFromGroup(src, id, true)
432 | else
433 | DestroyGroup(id)
434 | end
435 | end
436 | else
437 | RemovePlayerFromGroup(src,id, true)
438 | end
439 | end)
440 |
441 |
442 | ESX.RegisterServerCallback('rep-tablet:callback:getGroupsApp', function(source, cb)
443 | local src = source
444 | if Players[src] then
445 | local id = getGroupByMembers(src)
446 | cb(true, Groups[id])
447 | else
448 | cb(false, Groups)
449 | end
450 | end)
451 |
452 | ESX.RegisterServerCallback('rep-tablet:callback:getGroupsJob', function(source, cb)
453 | cb(Config.JobCenter)
454 | end)
455 |
456 | ESX.RegisterServerCallback('rep-tablet:callback:CheckPlayerNames', function(source, cb, id)
457 | local src = source
458 | local xPlayer = ESX.GetPlayerFromId(src)
459 | if Groups[id] == nil then
460 | xPlayer.showNotification("That group doesn't exist")
461 | cb(false)
462 | end
463 | cb(Groups[id].members)
464 | end)
465 |
466 | ESX.RegisterServerCallback('rep-tablet:callback:getDataGroup', function(_, cb)
467 | cb(Groups)
468 | end)
469 |
470 | AddEventHandler('playerDropped', function()
471 | local src = source
472 | local id = getGroupByMembers(src)
473 | if id then
474 | if isGroupLeader(src, id) then
475 | if Groups[id].status == true then
476 | DestroyGroup(id)
477 | else
478 | local change = ChangeGroupLeader(id)
479 | if change then
480 | RemovePlayerFromGroup(src, id, true)
481 | else
482 | DestroyGroup(id)
483 | end
484 | end
485 | else
486 | RemovePlayerFromGroup(src, id, true)
487 | end
488 | end
489 | end)
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5501
3 | }
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/INSTALL.md:
--------------------------------------------------------------------------------
1 | Made by Rep Scripts
2 | Discord: https://discord.gg/WK7nYmDhrN (24/7 support and updates)
3 | Tebex: https://rep.tebex.io/
4 |
5 | # Dependencies
6 |
7 | - [QBCore Framework](https://github.com/qbcore-framework)
8 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/README.md:
--------------------------------------------------------------------------------
1 | **[Preview](https://youtu.be/xuSjrBG-gRY)**
2 | **[Github](https://github.com/Rep-Scripts/rep-tablet)**
3 |
4 | _Discord Invite:_ https://discord.gg/VxGs8ceG5W
5 |
6 | _Tebex:_ https://rep.tebex.io/
7 |
8 | _Youtube:_ https://www.youtube.com/@repscripts
9 |
10 | _CFX:_ https://forum.cfx.re/u/bahnmifps/activity/topics
11 |
12 | > ## **INTRODUCTION**
13 |
14 | So, we make groups jobs. From the early versions of ps-playergroups since August 2022, to the latest qb-phone Nopixel inspired.
15 |
16 | However, these versions came with features that we didnt like, and 4 months later, we have released our own versions.
17 |
18 | The tablet is made so our customers who dont use qb-phone to enjoy our group jobs.
19 |
20 | **There are no jobs or anything included with these files.**
21 | **Check out the jobs at our Tebex.**
22 |
23 | ---
24 |
25 | > ## **FEATURES**
26 |
27 | ## **1. Job Center**
28 |
29 | - Configurable jobs, job location, money, icon, people to work, etc...
30 | - Navigate to assigned location.
31 | - "Illegal jobs" can be seen using a VPN.
32 | - Search bar for jobs
33 |
34 | ## **2. Groups**
35 |
36 | - Once signed in to jobs, players can see idle/busy groups.
37 | - Can create groups with up to 4 members.
38 | - If has VPN, players names will be automatically generated to cover their identity.
39 |
40 | ## **3. Syncing**
41 |
42 | - Sync job progress between players.
43 | - Sync notifications and job details.
44 |
45 | ---
46 |
47 | > ## **INSTALLATION**
48 |
49 | Drag and drop...
50 |
51 | ---
52 |
53 | > ## **🛠️ UPDATES**
54 |
55 | **Update 1.0**
56 |
57 | - Release
58 |
59 | ---
60 |
61 | **Update 1.1**
62 |
63 | - _to be updated_
64 |
65 | ---
66 |
67 | > ## **DEPENDENCIES**
68 |
69 | - [QBcore Framework](https://github.com/qbcore-framework)
70 | - [ESX](https://github.com/esx-framework)
71 | - [PS- Ui] https://github.com/Project-Sloth/ps-ui
72 |
73 | ---
74 |
75 | > ## **Check out our other products** :star2:
76 |
77 | - [[QB/ESX] Group Postal Op Delivery. NoPixel 3.5 DoDo Inspired](https://forum.cfx.re/t/qb-esx-group-postal-op-delivery-nopixel-3-5-dodo-inspired/4894624/29)
78 | - [NoPixel Inspired Group Sanitation Job v2](https://forum.cfx.re/t/nopixel-inspired-group-sanitation-job-v2/4929184/5)
79 | - [NoPixel Inspired Oxy Run w/ Money Laundering](https://forum.cfx.re/t/nopixel-inspired-oxy-run-w-money-laundering/4941107/10)
80 | - [NoPixel Inspired Chop Shop. With Phone Progresses!](https://forum.cfx.re/t/nopixel-inspired-chop-shop-with-phone-progresses/4942864/5)
81 | - [[PAID] [QBCORE] Advanced Realistic Trunk Space](https://forum.cfx.re/t/paid-qbcore-advanced-realistic-trunk-space/4891965/2)
82 | - [[RELEASE] [PAID] QBCore Realistic Vehiclekey with Hacking Device](https://forum.cfx.re/t/release-paid-qbcore-realistic-vehiclekey-with-hacking-device/4891955/10)
83 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/app.js:
--------------------------------------------------------------------------------
1 | REP = {};
2 | REP.Tablet = {};
3 | REP.Tablet.Functions = {};
4 | REP.Tablet.Animations = {};
5 | REP.Tablet.Notifications = {};
6 | REP.Tablet.Notifications.Custom = {};
7 |
8 | REP.Tablet.Data = {
9 | isOpen: false,
10 | PlayerData: {},
11 | };
12 |
13 | REP.Tablet.Config = {}
14 | var found = false;
15 |
16 | $(function() {
17 | $(".success_icon").hide();
18 | $("#job-app").on("click", function(e) {
19 | e.preventDefault();
20 | LoadJobCenter();
21 | });
22 | $("#map-open").on("click", function(e) {
23 | REP.Tablet.Functions.CloseTablet();
24 | $.post('https://rep-tablet/openMap', JSON.stringify({}));
25 | });
26 |
27 | $(".tablet__back--mainscreen").on("click", function() {
28 | $("#job-screen").fadeOut("1500");
29 | $("#create-screen").fadeOut("1500");
30 | $("#group-screen").fadeOut("1500");
31 | $("#tasks-screen").fadeOut("1500");
32 | $("#main-screen").show();
33 | });
34 |
35 | $("#date").html(getDate());
36 | $(".tablet__info h3").html(getTime());
37 |
38 | REP.Tablet.Functions.OpenTablet = function() {
39 | $("#tablet").fadeIn("1500");
40 | REP.Tablet.Data.IsOpen = true;
41 | };
42 |
43 | REP.Tablet.Functions.CloseTablet = function() {
44 | // $("#job-screen").fadeOut("1500");
45 | // $("#create-screen").fadeOut("1500");
46 | // $("#group-screen").fadeOut("1500");
47 | // $("#tasks-screen").fadeOut("1500");
48 | $("#tablet").fadeOut("1500");
49 | $.post('https://rep-tablet/Close');
50 | REP.Tablet.Data.IsOpen = false;
51 | };
52 |
53 | REP.Tablet.Animations.BottomSlideUp = function(Object, Timeout, Percentage) {
54 | $(Object).css({'display':'block'}).animate({
55 | bottom: Percentage+"%",
56 | }, Timeout);
57 | };
58 |
59 | REP.Tablet.Animations.BottomSlideDown = function(Object, Timeout, Percentage) {
60 | $(Object).css({'display':'block'}).animate({
61 | bottom: Percentage+"%",
62 | }, Timeout, function(){
63 | $(Object).css({'display':'none'});
64 | });
65 | };
66 |
67 | REP.Tablet.Animations.TopSlideDown = function(Object, Timeout, Percentage) {
68 | $(Object).css({'display':'block'}).animate({
69 | top: Percentage+"%",
70 | }, Timeout);
71 | };
72 |
73 | REP.Tablet.Animations.TopSlideUp = function(Object, Timeout, Percentage) {
74 | $(Object).css({'display':'block'}).animate({
75 | top: Percentage+"%",
76 | }, Timeout, function(){
77 | $(Object).css({'display':'none'});
78 | });
79 | };
80 |
81 | REP.Tablet.Animations.fadeInAnim = function(Object, Timeout) {
82 | $(Object).css({
83 | 'display': 'block',
84 | 'opacity': '1',
85 | 'transition': 'opacity .25s ease'
86 | }, Timeout);
87 | };
88 |
89 | REP.Tablet.Animations.fadeOutAnim = function(Object, Timeout) {
90 | $(Object).css({
91 | 'display': 'block',
92 | 'opacity': '0',
93 | 'transition': 'opacity .25s ease'
94 | }, Timeout, function(){
95 | $(Object).css({'display':'none'});
96 | });
97 | };
98 |
99 | REP.Tablet.Functions.LoadPlayerData = function(data) {
100 | REP.Tablet.Data.PlayerData = data;
101 |
102 | }
103 |
104 | REP.Tablet.Functions.LoadConfig = function(data) {
105 | REP.Tablet.Config = data;
106 | }
107 |
108 |
109 | REP.Tablet.Notifications.Custom.Add = function(icon, title, text, color, timeout, accept, deny) {
110 | $.post('https://rep-tablet/HasTablet', JSON.stringify({}), function(HasTablet) {
111 | if (HasTablet) {
112 | if (REP.Tablet.Notifications.Timeout !== undefined && REP.Tablet.Notifications.Timeout !== null) {
113 | clearTimeout(REP.Tablet.Notifications.Timeout);
114 | }
115 | REP.Tablet.Notifications.Timeout = null;
116 |
117 | if (timeout == null || timeout == undefined) {
118 | timeout = 1500;
119 | }
120 | if (color != null && color != undefined) {
121 | $(".notification-icon-new").css({"color": color});
122 | $(".notification-title-new").css({"color":"#FFFFFF"});
123 |
124 | } else if (color == "default" || color == null || color == undefined) {
125 | $(".notification-icon-new").css({"color":"#FFFFFF"});
126 | $(".notification-title-new").css({"color":"#FFFFFF"});
127 | }
128 | playSound("notify.ogg", "./sounds/", 0.6);
129 | REP.Tablet.Animations.TopSlideDown(".__tablet--notification-container-new", 600, 1);
130 | $(".notification-icon-new").html(' ');
131 | $(".notification-title-new").html(title);
132 | $(".notification-text-new").html(text);
133 | $(".notification-time-new").html("just now");
134 | if (accept != "NONE"){
135 | $(".notification-accept").html(' ');
136 | }
137 | if (deny != "NONE"){
138 | $(".notification-deny").html(' ');
139 | }
140 |
141 | if (timeout != "NONE"){
142 | if (REP.Tablet.Notifications.Timeout !== undefined && REP.Tablet.Notifications.Timeout !== null) {
143 | clearTimeout(REP.Tablet.Notifications.Timeout);
144 | }
145 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
146 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
147 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
148 | }, 500)
149 | REP.Tablet.Notifications.Timeout = null;
150 | }, timeout);
151 | };
152 | };
153 | });
154 | };
155 |
156 | REP.Tablet.Notifications.Add = function(icon, title, text, color, timeout) {
157 | $.post('https://rep-tablet/HasTablet', JSON.stringify({}), function(HasTablet) {
158 | if(HasTablet) {
159 | if (timeout == null && timeout == undefined) {
160 | timeout = 1500;
161 | }
162 |
163 | if (REP.Tablet.Notifications.Timeout == undefined || REP.Tablet.Notifications.Timeout == null) {
164 | if (color != null || color != undefined) {
165 | $(".notification-icon").css({"color":color});
166 | $(".notification-title").css({"color":color});
167 | } else if (color == "default" || color == null || color == undefined) {
168 | $(".notification-icon").css({"color":"#e74c3c"});
169 | $(".notification-title").css({"color":"#e74c3c"});
170 | }
171 |
172 | REP.Tablet.Animations.TopSlideDown(".__tablet--notification-container", 600, 1);
173 | $(".notification-icon").html(' ');
174 | $(".notification-title").html(title);
175 | $(".notification-text").html(text);
176 | $(".notification-time").html("just now");
177 | if (timeout != "NONE"){
178 | if (REP.Tablet.Notifications.Timeout !== undefined || REP.Tablet.Notifications.Timeout !== null) {
179 | clearTimeout(REP.Tablet.Notifications.Timeout);
180 | }
181 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
182 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
183 |
184 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
185 |
186 | }, 500)
187 | REP.Tablet.Notifications.Timeout = null;
188 | }, timeout);
189 | }
190 | } else {
191 | if (color != null || color != undefined) {
192 | $(".notification-icon").css({"color":color});
193 | $(".notification-title").css({"color":color});
194 | } else {
195 | $(".notification-icon").css({"color":"#e74c3c"});
196 | $(".notification-title").css({"color":"#e74c3c"});
197 | }
198 |
199 | $(".notification-icon").html(' ');
200 | $(".notification-title").html(title);
201 | $(".notification-text").html(text);
202 | $(".notification-time").html("just now");
203 | if (timeout != "NONE"){
204 | if (REP.Tablet.Notifications.Timeout !== undefined || REP.Tablet.Notifications.Timeout !== null) {
205 | clearTimeout(REP.Tablet.Notifications.Timeout);
206 | }
207 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
208 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
209 | REP.Tablet.Notifications.Timeout = setTimeout(function(){
210 |
211 | }, 500)
212 | REP.Tablet.Notifications.Timeout = null;
213 | }, timeout);
214 | }
215 | }
216 | }
217 | });
218 | }
219 |
220 | $(document).on('click', ".__tablet--notification-container", function() {
221 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
222 | REP.Tablet.Notifications.Timeout = null;
223 | })
224 |
225 | $(document).on('click', ".notification-accept", function() {
226 | $.post('https://rep-tablet/AcceptNotification', JSON.stringify({}));
227 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
228 | REP.Tablet.Notifications.Timeout = null;
229 | });
230 |
231 | $(document).on('click', ".notification-deny", function() {
232 | $.post('https://rep-tablet/DenyNotification', JSON.stringify({}));
233 | REP.Tablet.Notifications.Timeout = null;
234 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
235 | });
236 |
237 | $("body").on("keyup", function (e) {
238 | if (e.which == 27) {
239 | REP.Tablet.Functions.CloseTablet();
240 | };
241 | });
242 |
243 | window.addEventListener('message', function(e) {
244 | if (e.data.action === 'open') {
245 | // $("#tasks-screen").hide();
246 | // $("#group-screen").hide();
247 | // $("#create-screen").hide();
248 | // $("#job-screen").hide();
249 | $("#user-name").html(e.data.name);
250 | REP.Tablet.Functions.LoadPlayerData(e.data.data);
251 | REP.Tablet.Functions.OpenTablet();
252 | REP.Tablet.Data.isOpen = true;
253 | } else if (e.data.action === 'CustomNotification') {
254 | REP.Tablet.Notifications.Add(e.data.TabletNotify.icon, e.data.TabletNotify.title, e.data.TabletNotify.text, e.data.TabletNotify.color, e.data.TabletNotify.timeout);
255 | } else if (e.data.action === 'loadConfig') {
256 | REP.Tablet.Functions.LoadConfig(e.data.config);
257 | } else if (e.data.action === 'ReQuest') {
258 | REP.Tablet.Notifications.Custom.Add(e.data.TabletNotify.icon, e.data.TabletNotify.title, e.data.TabletNotify.text, e.data.TabletNotify.color, e.data.TabletNotify.timeout, e.data.TabletNotify.accept, e.data.TabletNotify.deny);
259 | } else if (e.data.action==='closeCustomNotification'){
260 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
261 | } else if (e.data.action === 'closeAllNotification'){
262 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
263 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container", 600, -10);
264 | }
265 | });
266 |
267 | function getDate() {
268 | var date = new Date();
269 | var day = date.getDay();
270 | var fristDay = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
271 | var month = (date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : (date.getMonth() + 1);
272 | var year = date.getFullYear();
273 | var dayArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
274 | var occasion = dayArray[day];
275 | var currentDate = occasion + ", " + fristDay + "/" + month + "/" + year;
276 | return currentDate;
277 | };
278 |
279 | function getTime() {
280 | var date = new Date();
281 | var hour = date.getHours();
282 | var minute = date.getMinutes();
283 | var amOrPm = hour >= 12 ? 'PM' : 'AM';
284 | hour = hour % 12;
285 | hour = hour ? hour : 12;
286 | minute = minute < 10 ? '0'+ minute : minute;
287 | var strTime = `${hour}:${minute} ${amOrPm} `;
288 | return strTime;
289 | };
290 |
291 | $("#search").on("keyup", function() {
292 | var value = $(this).val().toLowerCase();
293 | $(".tablet__job--item").filter(function() {
294 | $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
295 | });
296 | });
297 | });
298 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/groups.js:
--------------------------------------------------------------------------------
1 | var loadScreen = 7500; // Dont Touch This
2 | var loadSuccess = 6000; // Dont Touch This
3 | var min = 5000; // 5 seconds
4 | var max = 10000; // 10 seconds
5 | var minutes = 00;
6 | var seconds = 00;
7 | var tens = 00;
8 | var appendTens = document.getElementById("tens");
9 | var appendSeconds = document.getElementById("seconds");
10 | var appendminutes = document.getElementById("minutes");
11 | var Interval;
12 | var groupID;
13 | var data1;
14 | var data2;
15 | var jobPlayer;
16 | var randomTime = Math.floor(Math.random() * (max - min + 1)) + min;
17 | let notReadyButtonAdded = false;
18 |
19 | $(document).on("click", "#create-group", function(e) {
20 | e.preventDefault();
21 | $("#main-screen").hide();
22 | $("#create-screen").hide();
23 | $(".success_icon").hide();
24 | $(".text p").html("Please Wait...");
25 | $(".loader__wrapper").show();
26 | $("#loader-screen").show();
27 | setTimeout(function() {
28 | $(".loader__wrapper").hide();
29 | $(".success_icon").show();
30 | $(".text p").html("Created successfully!");
31 | }, loadSuccess);
32 | setTimeout(function() {
33 | $("#loader-screen").fadeOut("1500");
34 | $("#group-screen").fadeIn("1500");
35 | $.post("https://rep-tablet/CreateJobGroup", JSON.stringify({}), function() {});
36 | }, loadScreen);
37 | });
38 |
39 | function showNotification() {
40 | playSound("notify.ogg", "./sounds/", 0.6);
41 | $.post("https://rep-tablet/readyToJob", JSON.stringify({}), function() {});
42 | }
43 |
44 | function playSound(file, dir, volume) {
45 | var audio = new Audio(dir+file);
46 | audio.volume = volume;
47 | audio.play();
48 | }
49 |
50 | function closeAllScreen() {
51 | $("#job-screen").hide();
52 | $("#create-screen").hide();
53 | $("#group-screen").hide();
54 | $("#tasks-screen").hide();
55 | }
56 |
57 | $(document).on("click", "#check-out", function(e) {
58 | e.preventDefault();
59 | $.post("https://rep-tablet/checkOut", JSON.stringify({}), function() {});
60 | });
61 |
62 | $(document).on("click", "#job-ready", function(e) {
63 | e.preventDefault();
64 | $("#job-ready").addClass("checked");
65 | $("#job-ready p").text("waiting for job...");
66 | $(".spinner").removeClass("bxs-briefcase").addClass("bx-loader-alt spin");
67 |
68 | if (!$("#job-notready").length) {
69 | $("#room-actions").append(
70 | '' +
71 | 'not ready
' +
72 | ' ' +
73 | ' '
74 | );
75 | }
76 | setTimeout(showNotification, REP.Tablet.Config[jobPlayer].time.first);
77 | });
78 |
79 | $(document).on("click", "#job-notready", function(e) {
80 | e.preventDefault();
81 | $("#job-ready").removeClass("checked");
82 | $("#job-ready p").text("ready for work");
83 | $(".spinner").removeClass("bx-loader-alt spin").addClass("bxs-briefcase");
84 | $("#job-notready").remove();
85 | notReadyButtonAdded = false;
86 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
87 | });
88 |
89 | $(document).on("click", "#join-group", function (e) {
90 | e.preventDefault();
91 | var id = $(this).data('id');
92 | $.post("https://rep-tablet/RequestToJoin", JSON.stringify({id: id}), function() {});
93 | });
94 |
95 | $(document).on("click", "#disband-group", function(e) {
96 | var id = $(this).data('id');
97 | $.post("https://rep-tablet/DisbandGroup", JSON.stringify({id: id}), function() {});
98 | });
99 |
100 | $(document).on("click", "#leave-group", function(e) {
101 | var id = $(this).data('id');
102 | $.post("https://rep-tablet/LeaveGroup", JSON.stringify({id: id}), function() {});
103 | });
104 |
105 | $(document).on("click", "#expand-modal", function(e) {
106 | e.preventDefault();
107 | $("#task-overlay").fadeIn("1500");
108 | $("#task-modal").fadeIn("1500");
109 | });
110 |
111 | $(document).on("click", "#task-close", function(e) {
112 | e.preventDefault();
113 | $("#task-overlay").fadeOut("1500");
114 | $("#task-modal").fadeOut("1500");
115 | });
116 |
117 | function addGroupJobs(data) {
118 | if (data.status == true) {
119 | closeAllScreen();
120 | $("#tasks-screen").show();
121 | let tasksPerRow = 2;
122 | $("#tasks-list").html("");
123 | clearInterval(Interval);
124 | Interval = setInterval(startTimer, 10);
125 | let rowHTML = '';
126 | let taskCounter = 0;
127 | for (const [k, v] of Object.entries(data.stage)) {
128 | let max = 1;
129 | let count = 0;
130 | if (v.max) max = v.max;
131 | if (v.count) count = v.count;
132 |
133 | if (taskCounter % tasksPerRow === 0) {
134 | rowHTML += '';
135 | }
136 |
137 | let addOption;
138 | if (v.isDone) {
139 | addOption =
140 | `
141 |
142 |
143 |
144 |
${v.name}
145 |
146 |
147 |
${max} / ${max}
148 |
149 |
150 | `;
151 | } else {
152 | addOption =
153 | `
154 |
155 |
156 |
157 |
${v.name}
158 |
159 |
160 |
${count} / ${max}
161 |
162 |
163 | `;
164 | }
165 |
166 |
167 | rowHTML += addOption;
168 | taskCounter++;
169 |
170 | if (taskCounter % tasksPerRow === 0) {
171 | rowHTML += '
';
172 | } else {
173 | rowHTML += '
';
174 | }
175 | $(".__tablet--modal-content").html(v.name);
176 | }
177 | $("#tasks-list").append(rowHTML);
178 | } else {
179 | closeAllScreen();
180 | $("#group-screen").show();
181 | var memberList = $('.__tablet--member-list');
182 | memberList.html("");
183 | var itemCounter = 0;
184 | var rowHTML = '';
185 | var leaderName = "";
186 | var leaderCID = 0
187 | for (const [k, v] of Object.entries(data.members)) {
188 | if (v.player === data.leader) {
189 | leaderName = v.name;
190 | leaderCID = v.cid;
191 | }
192 | }
193 | var leaderHTML = '
';
194 | leaderHTML += '
';
195 | leaderHTML += '
leader
';
196 | leaderHTML += '
' + leaderName + '
';
197 | leaderHTML += '
';
198 | leaderHTML += '
';
199 | rowHTML += leaderHTML;
200 | itemCounter++;
201 |
202 | for (const [k, v] of Object.entries(data.members)) {
203 | if (k > 0) {
204 | var memberHTML = '
';
205 | memberHTML += '
';
206 | memberHTML += '
member
';
207 | memberHTML += '
' + v.name + '
';
208 | memberHTML += '
';
209 | memberHTML += '
';
210 | rowHTML += memberHTML;
211 | itemCounter++;
212 |
213 | if (itemCounter == 4) {
214 | rowHTML += '
';
215 | memberList.append(rowHTML);
216 | rowHTML = '';
217 | itemCounter = 0;
218 | }
219 | }
220 | }
221 | var ctd = REP.Tablet.Data.PlayerData.citizenid;
222 | if (ctd !== leaderCID) {
223 | $("#room-actions").html('
' +
224 | 'leave group
' +
225 | ' ' +
226 | ' ');
227 | } else {
228 | $("#room-actions").html(
229 | '
' +
230 | 'ready for work
' +
231 | ' ' +
232 | ' ' +
233 | '
' +
234 | 'disband group
' +
235 | ' ' +
236 | ' '
237 | );
238 | }
239 | if (itemCounter > 0) {
240 | rowHTML += '
';
241 | memberList.append(rowHTML);
242 | };
243 | };
244 | };
245 |
246 | function addGroup(data, job) {
247 | var addOption;
248 | var addOption1;
249 | var row = ``;
250 | var row1 = `
`;
251 | var idleList = $("#group-idle");
252 | var idle = 0;
253 | var busy = 0;
254 | idleList.html("");
255 | var busyList = $("#group-busy");
256 | busyList.html("");
257 | if (data && data.length > 0) {
258 | Object.keys(data).map(function(element) {
259 | if (data[element]) {
260 | if (!data[element].status && data[element].job === job) {
261 | idle = idle + 1;
262 | addOption = `
263 |
264 |
265 |
266 |
${data[element].gName}
267 |
268 |
269 |
270 |
271 |
${REP.Tablet.Config[job].mem}
272 |
273 |
274 |
275 |
${data[element].users}
276 |
277 |
278 |
279 |
280 |
join group
281 |
282 |
283 | `;
284 | row += addOption;
285 | if (idle % 3 === 0) {
286 | row += '
';
287 | idleList.append(row);
288 | row = `
`;
289 | }
290 | } else if (data[element].status && data[element].job === job) {
291 | busy = busy + 1;
292 | addOption1 =
293 | `
294 |
295 |
296 |
297 |
${data[element].gName}
298 |
299 |
300 |
301 |
302 |
${REP.Tablet.Config[job].mem}
303 |
304 |
305 |
306 |
${data[element].users}
307 |
308 |
309 |
310 | `;
311 | row1 += addOption1;
312 | if (busy % 3 === 0) {
313 | row1 += '
';
314 | busyList.append(row1);
315 | row1 = `
`;
316 | }
317 | }
318 | }
319 | });
320 | row += '
'; // Add closing tag for idle row
321 | idleList.append(row);
322 | row1 += '
'; // Add closing tag for busy row
323 | busyList.append(row1);
324 |
325 | if (idle === 0) {
326 | idleList.html(`There are no idle groups available
`);
327 | }
328 | if (busy === 0) {
329 | busyList.html(`There are no busy groups available
`);
330 | }
331 | } else {
332 | idleList.html(`There are no idle groups available
`);
333 | busyList.html(`There are no busy groups available
`);
334 | }
335 | };
336 |
337 | function startTimer() {
338 | tens++;
339 | if(tens <= 9){
340 | appendTens.innerHTML = "0" + tens;
341 | }
342 |
343 | if (tens > 9){
344 | appendTens.innerHTML = tens;
345 |
346 | }
347 |
348 | if (tens > 99) {
349 | seconds++;
350 | appendSeconds.innerHTML = "0" + seconds;
351 | tens = 0;
352 | appendTens.innerHTML = "0" + 0;
353 | }
354 |
355 | if (seconds > 9){
356 | appendSeconds.innerHTML = seconds;
357 | }
358 |
359 | if (seconds > 60){
360 | minutes++;
361 | appendminutes.innerHTML = "0" + minutes;
362 | seconds = 0;
363 | appendSeconds.innerHTML = "0" + 0;
364 | }
365 | };
366 |
367 | $(function() {
368 | window.addEventListener('message', function(e) {
369 | if (e.data.action === 'refreshApp') {
370 | closeAllScreen();
371 | jobPlayer = e.data.job;
372 | $("#create-screen").fadeIn("1500");
373 | if (REP.Tablet.Config[e.data.job]) {
374 | $(".__tablet--header-content").html(REP.Tablet.Config[e.data.job].label);
375 | }
376 | addGroup(e.data.data, e.data.job);
377 | } else if (e.data.action === 'addGroupStage') {
378 | addGroupJobs(e.data.status);
379 | } else if (e.data.action === 'reLoop') {
380 | setTimeout(showNotification, REP.Tablet.Config[jobPlayer].time.second);
381 | } else if (e.data.action === 'cancelReady') {
382 | e.preventDefault();
383 | $("#job-ready").removeClass("checked");
384 | $("#job-ready p").text("ready for work");
385 | $(".spinner").removeClass("bx-loader-alt spin").addClass("bxs-briefcase");
386 | $("#job-notready").remove();
387 | notReadyButtonAdded = false;
388 | REP.Tablet.Animations.TopSlideUp(".__tablet--notification-container-new", 600, -10);
389 | }
390 | });
391 | });
392 |
393 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/app/facebook_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/app/facebook_app.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/app/google_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/app/google_app.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/app/instagram_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/app/instagram_app.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/app/job_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/app/job_app.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/app/settings_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/app/settings_app.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/cloudy.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/logo.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/tablet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/tablet.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/tablet_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/tablet_background.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/tablet_background2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/tablet_background2.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/imgs/tablet_job-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/imgs/tablet_job-background.png
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/jobCenter.js:
--------------------------------------------------------------------------------
1 | $(document).on("click", "#get-location", function (e) {
2 | e.preventDefault();
3 | var event = $(this).data("event");
4 | $.post("https://rep-tablet/CreateBlip", JSON.stringify({
5 | event: event,
6 | }));
7 | });
8 |
9 | function addJobsList(data) {
10 | $(".tablet__job--list").html("");
11 | for (let i = 0; i < data.length; i++) {
12 | const v = data[i];
13 | var addOption =
14 | `
15 |
16 |
17 |
18 |
19 |
20 |
${v.label}
21 |
22 |
23 |
24 | ${v.salary}
25 |
26 |
27 |
28 |
29 | ${v.mem}
30 |
31 |
32 |
33 |
34 | ${v.count}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
get location
42 |
43 |
`;
44 | $(".tablet__job--list").append(addOption);
45 | };
46 | };
47 |
48 | function LoadJobCenter() {
49 | $.post('https://rep-tablet/GetData', JSON.stringify({}), function() {});
50 | };
51 |
52 | $(function() {
53 | window.addEventListener('message', function(e) {
54 | if (e.data.action === 'jobcenter') {
55 | closeAllScreen();
56 | $("#job-screen").fadeIn("1500");
57 | addJobsList(e.data.data);
58 | };
59 | });
60 | });
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/notify.css:
--------------------------------------------------------------------------------
1 | .__tablet--notification-container,
2 | .__tablet--notification-container-new {
3 | position: absolute;
4 | height: 7vh;
5 | width: 40vh;
6 | background: rgba(58, 65, 71, 0.806);
7 | margin: 0 auto;
8 | left: 0;
9 | right: 0;
10 | top: -10%;
11 | overflow: hidden;
12 | box-shadow: inset 0px 0px 10px 0px rgba(0, 0, 0, 0.11);
13 | z-index: 9999999999;
14 | border-radius: .4vw;
15 | padding: 1.2vh 1vw;
16 | }
17 |
18 | .__tablet--notification-top {
19 | display: flex;
20 | align-items: center;
21 | width: 100%;
22 | justify-content: space-between;
23 | margin-bottom: .48vh;
24 | }
25 |
26 | .__tablet--notification-container-new .__tablet--notification-top {
27 | margin-bottom: .25vh;
28 | }
29 |
30 | .__tablet--notification-item {
31 | display: flex;
32 | align-items: center;
33 | width: 50%;
34 | gap: .5vw;
35 | }
36 |
37 | .notification-icon,
38 | .notification-icon-new {
39 | width: 3vh;
40 | height: 50%;
41 | text-align: center;
42 | line-height: 2.8vh;
43 | color: var(--white-color);
44 | font-size: 2.4vh;
45 | }
46 |
47 | .notification-title,
48 | .notification-title-new {
49 | font-size: 1.5vh;
50 | color: var(--white-color);
51 | text-transform: var(--main-font-transform);
52 | font-weight: 600;
53 | }
54 |
55 | .notification-time,
56 | .notification-time-new {
57 | font-size: 1.5vh;
58 | color: rgb(255, 255, 255);
59 | text-transform: capitalize;
60 | }
61 |
62 | .notification-text,
63 | .notification-text-new {
64 | font-size: 1.4vh;
65 | color: rgb(255, 255, 255);
66 | white-space: nowrap;
67 | overflow: hidden;
68 | text-overflow: ellipsis;
69 | text-align: left;
70 | }
71 |
72 | .notification-text {
73 | max-width: 100%;
74 | }
75 |
76 | .notification-text-new {
77 | max-width: 65%;
78 | }
79 |
80 | .__tablet--notification-bottom {
81 | width: 100%;
82 | display: flex;
83 | align-items: center;
84 | justify-content: space-between;
85 | }
86 |
87 | .__tablet--notification-btn {
88 | display: flex;
89 | align-items: center;
90 | gap: .25vw;
91 | }
92 |
93 | .__tablet--notification-btn > * {
94 | transition: .25s ease;
95 | }
96 |
97 | .notification-accept {
98 | font-size: 1.9vh;
99 | color: rgb(26, 176, 26);
100 | cursor: pointer;
101 | }
102 |
103 | .notification-accept:hover {
104 | color: rgb(34, 233, 34);
105 | }
106 |
107 | .notification-deny {
108 | font-size: 1.9vh;
109 | color: rgb(201, 28, 28);
110 | cursor: pointer;
111 | }
112 |
113 | .notification-deny:hover {
114 | color: rgb(238, 33, 33);
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/sounds/notify.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rep-Scripts/rep-tablet/ea15b3da6e5e8a335292cc641cdb0db446f85629/qb-core ver/rep-tablet/Ui/sounds/notify.ogg
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/twitter-style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Barlow&display=swap');
2 | @import url('https://fonts.googleapis.com/css2?family=Quicksand&display=swap');
3 | @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
4 | @import url("./animate.min.css");
5 |
6 | * {
7 | -webkit-box-sizing: border-box;
8 | -moz-box-sizing: border-box;
9 | box-sizing: border-box;
10 | -moz-user-select: none;
11 | -khtml-user-select: none;
12 | -webkit-user-select: none;
13 | -ms-user-select: none;
14 | user-select: none;
15 | list-style: none;
16 | text-decoration: none;
17 | font-family: 'Roboto', sans-serif;
18 | }
19 |
20 | :root {
21 | --main-font-transform: uppercase;
22 | --main-light-font: 400;
23 | --main-bold-font: 700;
24 | --white-color: #F5F8FA;
25 | --color-2: rgb(188, 188, 188);
26 | }
27 |
28 | html {
29 | font-size: 62.5%;
30 | }
31 |
32 | html, body {
33 | height: 100%;
34 | }
35 |
36 | body {
37 | margin: 0;
38 | padding: 0;
39 | overflow: hidden;
40 | }
41 |
42 | .animate__animated.animate__delay-1s {
43 | -webkit-animation-delay: .1s;
44 | animation-delay: .1s;
45 | }
46 |
47 | .animate__animated.animate__delay-2s {
48 | -webkit-animation-delay: .2s;
49 | animation-delay: .2s;
50 | }
51 |
52 | .animate__animated.animate__delay-3s {
53 | -webkit-animation-delay: .3s;
54 | animation-delay: .3s;
55 | }
56 |
57 | .animate__animated.animate__delay-4s {
58 | -webkit-animation-delay: .4s;
59 | animation-delay: .4s;
60 | }
61 |
62 | .animate__animated.animate__delay-5s {
63 | -webkit-animation-delay: .5s;
64 | animation-delay: .5s;
65 | }
66 |
67 | .animate__animated.animate__delay-6s {
68 | -webkit-animation-delay: .6s;
69 | animation-delay: .6s;
70 | }
71 |
72 | .animate__animated.animate__delay-7s {
73 | -webkit-animation-delay: .7s;
74 | animation-delay: .7s;
75 | }
76 |
77 | .animate__animated.animate__delay-8s {
78 | -webkit-animation-delay: .8s;
79 | animation-delay: .8s;
80 | }
81 |
82 | .animate__animated.animate__delay-9s {
83 | -webkit-animation-delay: .9s;
84 | animation-delay: .9s;
85 | }
86 |
87 | .animate__animated.animate__delay-10s {
88 | -webkit-animation-delay: 1s;
89 | animation-delay: 1s;
90 | }
91 |
92 | .animate__animated.animate__delay-11s {
93 | -webkit-animation-delay: 1.1s;
94 | animation-delay: 1.1s;
95 | }
96 |
97 | .animate__animated.animate__delay-12s {
98 | -webkit-animation-delay: 1.2s;
99 | animation-delay: 1.2s;
100 | }
101 |
102 | .animate__animated.animate__delay-13s {
103 | -webkit-animation-delay: 1.3s;
104 | animation-delay: 1.4s;
105 | }
106 |
107 | .animate__animated.animate__delay-14s {
108 | -webkit-animation-delay: 1.5s;
109 | animation-delay: 1.5s;
110 | }
111 |
112 | .animate__animated.animate__delay-15s {
113 | -webkit-animation-delay: 1.6s;
114 | animation-delay: 1.6s;
115 | }
116 |
117 | .animate__animated.animate__delay-16s {
118 | -webkit-animation-delay: 1.7s;
119 | animation-delay: 1.7s;
120 | }
121 |
122 | .animate__animated.animate__delay-17s {
123 | -webkit-animation-delay: 1.8s;
124 | animation-delay: 1.8s;
125 | }
126 |
127 | .animate__animated.animate__delay-18s {
128 | -webkit-animation-delay: 1.9s;
129 | animation-delay: 1.9s;
130 | }
131 |
132 | .animate__animated.animate__delay-19s {
133 | -webkit-animation-delay: 2s;
134 | animation-delay: 2s;
135 | }
136 |
137 | .animate__animated.animate__delay-20s {
138 | -webkit-animation-delay: 2.1s;
139 | animation-delay: 2.1s;
140 | }
141 |
142 | #container {
143 | position: relative;
144 | left: 0;
145 | top: 0;
146 | width: 100vw;
147 | height: 100vh;
148 | }
149 |
150 | .overlay {
151 | position: absolute;
152 | top: 0;
153 | left: 0;
154 | width: 100%;
155 | height: 100%;
156 | background: rgba(0, 0, 0, .24);
157 | }
158 |
159 | .tablet__border {
160 | position: absolute;
161 | top: 50%;
162 | left: 50%;
163 | transform: translate(-50%, -50%);
164 | width: 60vw;
165 | height: 65vh;
166 | background: url("./imgs/tablet.png") no-repeat center center;
167 | background-size: 100% 100%;
168 | display: flex;
169 | align-items: center;
170 | justify-content: center;
171 | position: relative;
172 | }
173 |
174 | .tablet__container {
175 | position: relative;
176 | width: 76.2%;
177 | height: 80%;
178 | position: relative;
179 | }
180 |
181 | .tablet__wrapper {
182 | width: 100%;
183 | height: 100%;
184 | margin-top: .2vh;
185 | margin-left: -.1vw;
186 | }
187 |
188 | .__tablet {
189 | width: 100%;
190 | height: 100%;
191 | position: relative;
192 | padding: 6.5vh 2.5vw;
193 | }
194 |
195 | .tablet__wrapper#main-screen {
196 | background: url("./imgs/tablet_background2.png") center center no-repeat;
197 | background-size: 100% 100%;
198 | border-radius: 1vw;
199 | }
200 |
201 | .tablet__wrapper#job-screen {
202 | /* background: url("./imgs/tablet_job-background.png") no-repeat center center; */
203 | /* background: #1a3457; */
204 | background: #141d26;
205 | background-size: 100% 100%;
206 | position: absolute;
207 | top: 50%;
208 | left: 50%;
209 | transform: translate(-50%, -50%);
210 | border-radius: 1vw;
211 | }
212 |
213 | .tablet__header {
214 | position: absolute;
215 | top: 0;
216 | left: -.1vw;
217 | width: 100%;
218 | height: 3vh;
219 | padding: 1.8vh 1vw;
220 | display: flex;
221 | justify-content: space-between;
222 | align-items: center;
223 | background: rgba(0, 0, 0, .4);
224 | border-top-left-radius: 1.15vw;
225 | border-top-right-radius: 1.15vw;
226 | z-index: 9999;
227 | }
228 |
229 | .tablet__header--items {
230 | display: flex;
231 | align-items: center;
232 | gap: .4vw;
233 | height: 100%;
234 | }
235 |
236 | .tablet__header--items:nth-of-type(odd) {
237 | width: 25%;
238 | }
239 |
240 | .tablet__header--items:nth-of-type(2) {
241 | width: 50%;
242 | justify-content: center;
243 | }
244 |
245 | .tablet__header--items:nth-of-type(3) {
246 | justify-content: flex-end;
247 | }
248 |
249 | .tablet__header--items i, p {
250 | font-size: 1.6vh;
251 | color: var(--white-color);
252 | }
253 |
254 |
255 |
256 |
257 | .tablet__apps {
258 | position: absolute;
259 | bottom: 0;
260 | left: 50%;
261 | width: 100%;
262 | height: 7vh;
263 | transform: translate(-50%, -50%);
264 | display: flex;
265 | align-items: center;
266 | justify-content: center;
267 | gap: 1vw;
268 | }
269 |
270 | .tablet__apps .tablet__app--item {
271 | width: 5vw;
272 | height: 100%;
273 | text-align: center;
274 | cursor: pointer;
275 | }
276 |
277 | .tablet__app--item:hover .tablet__app--content {
278 | color: var(--white-color);
279 | }
280 |
281 | .tablet__app--item:hover img {
282 | transform: translateY(-.5vh);
283 | }
284 |
285 | .tablet__app--item img {
286 | height: 4.5vh;
287 | margin-bottom: -.5vh;
288 | transition: .25s ease;
289 | }
290 |
291 | .tablet__app--content {
292 | font-size: 1.5vh;
293 | font-weight: 500;
294 | color: var(--color-2);
295 | transition: .25s ease;
296 | }
297 |
298 | .tablet__info {
299 | position: absolute;
300 | top: 24.5%;
301 | left: 50%;
302 | height: 5vh;
303 | display: flex;
304 | align-items: center;
305 | justify-content: center;
306 | gap: 1.5vw;
307 | transform: translate(-50%, -50%);
308 | }
309 |
310 | .tablet__info h3 {
311 | font-weight: 400;
312 | font-size: 4.8vh;
313 | color: var(--white-color);
314 | }
315 |
316 | .tablet__info h3 span {
317 | font-size: 2vh;
318 | }
319 |
320 | .tablet__info .bars {
321 | height: 100%;
322 | width: .08vw;
323 | margin-top: .6vh;
324 | background-color: rgb(255, 255, 255);
325 | }
326 |
327 | .tablet__info--weather {
328 | display: flex;
329 | align-items: center;
330 | gap: 1vw;
331 | }
332 |
333 | .tablet__info--weather img {
334 | height: 5vh;
335 | }
336 |
337 | .tablet__weather--top {
338 | font-size: 2.6vh;
339 | margin-top: 1.36vh;
340 | margin-bottom: -1.28vh;
341 | }
342 |
343 | .tablet__weather--bottom {
344 | font-size: 1.5vh;
345 | }
346 |
347 | .logo {
348 | width: 6.5vw;
349 | height: 11vh;
350 | position: absolute;
351 | top: 50%;
352 | left: 50%;
353 | transform: translate(-50%, -50%);
354 | }
355 |
356 | .__tablet--header {
357 | position: relative;
358 | z-index: 1;
359 | width: 100%;
360 | height: 10%;
361 | display: flex;
362 | align-items: center;
363 | justify-content: space-between;
364 | }
365 |
366 | .__tablet--header--left {
367 | display: flex;
368 | align-items: center;
369 | gap: .8vw;
370 | }
371 |
372 | .__tablet--header--left i {
373 | font-size: 4vh;
374 | /* color: rgb(71, 71, 71); */
375 | color: #F5F8FA;
376 | }
377 |
378 | .__tablet--header-content {
379 | text-transform: var(--main-font-transform);
380 | font-size: 3.2vh;
381 | /* color: rgb(71, 71, 71); */
382 | color: #F5F8FA;
383 |
384 |
385 | }
386 |
387 | .__tablet--search-container {
388 | width: 12vw;
389 | height: 4vh;
390 | position: relative;
391 | }
392 |
393 | .searchbox {
394 | width: 100%;
395 | height: 100%;
396 | overflow: hidden;
397 | }
398 |
399 | .search-input {
400 | position: absolute;
401 | left: 0;
402 | width: 100%;
403 | padding-right: 2.5vw;
404 | box-sizing: border-box;
405 | height: 5vh;
406 | border: 0;
407 | font-size: 1.6vh;
408 | background: transparent;
409 | color: #F5F8FA;
410 | outline: none;
411 | }
412 |
413 | .search-input::placeholder {
414 | color: #AAB8C2;
415 | }
416 |
417 | .searchbox button {
418 | position: absolute;
419 | right: 0;
420 | top: 0;
421 | width: 1.4vw;
422 | height: 2.5vh;
423 | outline: none;
424 | }
425 |
426 | .line {
427 | position: absolute;
428 | bottom: 0;
429 | left: 0;
430 | right: 0;
431 | margin: auto;
432 | width: 100%;
433 | height: .2vh;
434 | /* background: #ffffff85; */
435 | /* background: #48cffe; */
436 | background: #657786;
437 |
438 |
439 | }
440 |
441 | .submit {
442 | -webkit-appearance: none;
443 | background: transparent;
444 | border: 0;
445 | margin-top: .3vh;
446 | }
447 |
448 | .submit::before {
449 | content: "";
450 | position: absolute;
451 | width: 60%;
452 | height: 60%;
453 | left: 10%;
454 | top: 50%;
455 | box-sizing: border-box;
456 | border: .3vh solid #ffd10d;
457 | border-radius: 50%;
458 | }
459 |
460 | .submit::after {
461 | content: "";
462 | position: absolute;
463 | width: .15vw;
464 | height: .6vh;
465 | background: #ffd10d;
466 | transform-origin: 50% 0%;
467 | transform: rotate(-45deg);
468 | top: 95%;
469 | left: 60%;
470 | }
471 |
472 | .tablet__back--mainscreen {
473 | width: 1.7vw;
474 | height: 3.1vh;
475 | cursor: pointer;
476 | border-radius: 50%;
477 | position: absolute;
478 | top: 105%;
479 | left: 49%;
480 | opacity: 0;
481 | transform: translate(-50%, -50%);
482 | z-index: 9999;
483 | }
484 |
485 | .tablet__job--list {
486 | margin-top: 3vh;
487 | width: 105%;
488 | height: 37vh;
489 | overflow-y: scroll;
490 | overflow-x: hidden;
491 | }
492 |
493 | .tablet__job--list::-webkit-scrollbar {
494 | width: .28vw;
495 | display: none;
496 | }
497 |
498 | .tablet__job--item {
499 | width: 89%;
500 | height: 100%;
501 | /* background: linear-gradient(145deg, rgba(71, 71, 71, 0.7), #828282); */
502 | /* background: #142740; */
503 | background: #243447;
504 | box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
505 | border-top-left-radius: .25vw;
506 | border-top-right-radius: .25vw;
507 | border-bottom: .2vh solid #AAB8C2;
508 | display: flex;
509 | align-items: center;
510 | box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;
511 | }
512 |
513 | #get-job {
514 | font-size: 4vh;
515 | /* color: #9e9e9e; */
516 | /* color: #ffd10d; */
517 | color: #1DA1F2;
518 | cursor: pointer;
519 | transition: .25s ease;
520 | }
521 |
522 | dfn {
523 | position: relative;
524 | }
525 |
526 | dfn::after {
527 | content: attr(data-info);
528 | border-bottom: .25vh solid gold;
529 | display: inline;
530 | position: absolute;
531 | top: 10%;
532 | left: -65%;
533 | opacity: 0;
534 | display: flex;
535 | justify-content: center;
536 | text-transform: var(--main-font-transform);
537 | align-items: center;
538 | min-width: 4vw;
539 | height: 1.5vh;
540 | font-size: 1.05vh;
541 | padding: .5vw;
542 | font-weight: 700;
543 | border-radius: .25vw;
544 | background: rgba(49, 49, 49, 0.9);
545 | color: var(--white-color);
546 | pointer-events: none;
547 | transition: opacity 250ms, top 250ms;
548 | }
549 |
550 | dfn:hover {z-index: 999999;}
551 | dfn:hover::after {opacity: 1; top: -35%;}
552 |
553 | dfn:hover #get-job {
554 | color: #243447;
555 | }
556 |
557 | .icon {
558 | font-size: 4.8vh;
559 | color: var(--white-color);
560 | }
561 |
562 | .tablet__job--item--eles:nth-of-type(1) {
563 | width: 18%;
564 | height: 100%;
565 | display: flex;
566 | justify-content: center;
567 | align-items: center;
568 | }
569 |
570 | .tablet__job--item--eles:nth-of-type(2) {
571 | width: 42%;
572 | height: 100%;
573 | }
574 |
575 | .tablet__job--item--eles:nth-of-type(3) {
576 | width: 40%;
577 | height: 100%;
578 | display: flex;
579 | justify-content: flex-start;
580 | align-items: center;
581 | }
582 |
583 | .tablet__job--content {
584 | display: flex;
585 | align-items: flex-start;
586 | flex-direction: column;
587 | }
588 |
589 | .tablet__job--content--name {
590 | text-transform: capitalize;
591 | margin-bottom: -.5vh;
592 | margin-top: 1.25vh;
593 | font-size: 2vh;
594 | font-weight:600;
595 | }
596 |
597 | .tablet__job--content--bottom {
598 | display: flex;
599 | gap: 1vw;
600 | }
601 |
602 | .bottom__content {
603 | display: flex;
604 | align-items: center;
605 | gap: .8vw;
606 | }
607 |
608 | .salary__content {
609 | text-transform: capitalize;
610 | font-weight: 600;
611 | }
612 |
613 | .high {
614 | /* color: rgb(107, 255, 38); */
615 | color:#80ED99
616 | }
617 |
618 | .medium {
619 | /* color: rgb(255, 179, 38); */
620 | color:#F77F00
621 | }
622 |
623 | .low {
624 | color: #D62828;
625 | /* color: rgb(255, 112, 112); */
626 | }
627 |
628 | .tablet__job--item-description {
629 | line-height: 2.4vh;
630 | }
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/Ui/ui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | REP TABLET
12 |
13 |
14 |
15 |
25 |
26 |
42 |
43 |
44 |
45 |
46 |
62 |
63 |
64 |
65 |
66 |
Settings
67 |
68 |
69 |
70 |
Google
71 |
72 |
73 |
74 |
Job Center
75 |
76 |
77 |
78 |
Los Santos Map
79 |
80 |
81 |
82 |
Instagram
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
35° C
92 |
Ha Noi, Viet Nam
93 |
94 |
95 |
96 |
97 |
98 |
117 |
118 |
119 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
160 |
161 |
162 |
171 |
172 |
173 |
178 |
179 |
180 |
181 |
182 |
183 |
186 |
189 |
192 |
195 |
198 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
Please Wait...
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/client/cl_group.lua:
--------------------------------------------------------------------------------
1 | local inJob = false
2 | local requestCoolDown = false
3 | local isGroupLeader = false
4 | local vpn = false
5 | local groupID = 0
6 | local JobCenter = {}
7 | local request = false
8 |
9 | local function loadConfig()
10 | SendNUIMessage({
11 | action = "loadConfig",
12 | config = Config.JobCenter,
13 | })
14 | end
15 |
16 | exports("IsGroupLeader", function()
17 | return isGroupLeader
18 | end)
19 |
20 | exports("GetGroupID", function()
21 | return groupID
22 | end)
23 |
24 | local function ReQuest(title, text, icon, color, timeout, accept, deny)
25 | request = promise.new()
26 | SendNUIMessage({
27 | action = "ReQuest",
28 | TabletNotify = {
29 | title = title or "Rep Scripts",
30 | text = text or "MSG",
31 | icon = icon or "fas fa-home",
32 | color = color or "#FFBF00",
33 | timeout = timeout or 7500, -- Nếu là "NONE" thì sẽ không tự tắt
34 | accept = accept or "fas fa-check-circle",
35 | deny = deny or "fas fa-times-circle",
36 | },
37 | })
38 | local result = Citizen.Await(request)
39 | return result
40 | end
41 |
42 | RegisterNUICallback('openMap', function()
43 | ExecuteCommand('e tablet2')
44 | exports['ps-ui']:ShowImage("https://images-ext-2.discordapp.net/external/Fav1ERUT4HznSnjZopp2QH3DHYw2Yh1rLmzyaCgAJUI/https/saeshq2018.weebly.com/uploads/1/1/8/7/118771343/5470709-orig_orig.png?width=690&height=702")
45 | end)
46 |
47 | RegisterNUICallback('AcceptNotification', function()
48 | request:resolve(true)
49 | request = nil
50 | end)
51 |
52 | RegisterNUICallback('DenyNotification', function()
53 | request:resolve(false)
54 | request = nil
55 | end)
56 |
57 | exports("ReQuest", ReQuest)
58 |
59 | -- Khi bật App sẽ gửi về để xem có job hay không, nếu có job thì kiểm tra
60 | RegisterNUICallback('GetData', function(data, cb)
61 | local job = LocalPlayer.state.nghe
62 | if job then
63 | Core.Functions.TriggerCallback('rep-tablet:callback:getGroupsApp', function (bool, data)
64 | if bool then
65 | SendNUIMessage({
66 | action = "addGroupStage", -- Khi set State thì status về true, còn refresh App thì status của job về false. Nếu Stage == {} thì đưa về giao diện các thành viên trong nhóm
67 | status = data, -- cấu trúc của stage https://cdn.discordapp.com/attachments/1036820124784668692/1052217816528461894/image.png
68 | })
69 | else
70 | SendNUIMessage({
71 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
72 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận // Thông tin các nhóm
73 | job = LocalPlayer.state.nghe -- Nghề, lọc ra các nhóm trong bảng data có cùng nghề
74 | })
75 | end
76 | end)
77 | else --- jobcenter thì sẽ hiện danh sách các nghề
78 | SendNUIMessage({
79 | action = "jobcenter",
80 | data = JobCenter,
81 | })
82 | end
83 | end)
84 |
85 | -- Tạo blip đến chỗ làm việc
86 | RegisterNUICallback('CreateBlip', function(data)
87 | TriggerEvent(data.event)
88 | end)
89 |
90 | RegisterNUICallback('readyToJob', function()
91 | if groupID == 0 then return end
92 | local success = ReQuest("Job Offer", 'Would you like to begin this job?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
93 | if success == nil then return end
94 | if success then
95 | TriggerEvent('rep-tablet:client:readyforjob')
96 | else
97 | SendNUIMessage({
98 | action = "reLoop", -- Khi set State thì status về true, còn refresh App thì status của job về fail
99 | })
100 | end
101 | end)
102 |
103 | -- Tạo nhóm
104 | RegisterNUICallback('CreateJobGroup', function(data, cb) --employment
105 | local result = vpn
106 | TriggerServerEvent('rep-tablet:server:createJobGroup', result, LocalPlayer.state.nghe)
107 | isGroupLeader = true
108 | cb("ok")
109 | end)
110 |
111 | --Xin vào nhóm
112 | RegisterNUICallback('RequestToJoin', function (data, cb)
113 | if not requestCoolDown then
114 | requestCoolDown = true
115 | Core.Functions.Notify("Sent Request", "success")
116 | TriggerServerEvent('rep-tablet:server:requestJoinGroup', data)
117 | Wait(5000)
118 | requestCoolDown = false
119 | else
120 | Core.Functions.Notify("You need to wait before requesting again", "error")
121 | end
122 | end)
123 |
124 | RegisterNUICallback('checkOut', function (data, cb)
125 | if groupID ~= 0 or inJob then
126 | if inJob then
127 | SendNUIMessage({
128 | action = "closeAllNotification",
129 | })
130 | TriggerServerEvent('rep-tablet:server:checkout', groupID)
131 | LocalPlayer.state:set('nghe', nil, false)
132 | end
133 | end
134 | if groupID == 0 then
135 | TriggerEvent('rep-tablet:client:checkout')
136 | end
137 | SendNUIMessage({
138 | action = "jobcenter",
139 | data = JobCenter,
140 | })
141 | end)
142 |
143 | RegisterNetEvent('rep-tablet:client:closeAllNotification', function ()
144 | SendNUIMessage({
145 | action = "closeAllNotification",
146 | })
147 | end)
148 | -- Out khỏi nhóm
149 | RegisterNUICallback('LeaveGroup', function(data, cb) --data của nhóm ấn vào
150 | if not data then return end
151 | local success = ReQuest("Job Center", 'Are you sure you want to leave the group?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
152 | if success then
153 | isGroupLeader = false
154 | TriggerServerEvent('rep-tablet:server:LeaveGroup', groupID)
155 | cb("ok")
156 | end
157 | end)
158 |
159 | RegisterNUICallback('DisbandGroup', function(data, cb) --data của nhóm ấn vào
160 | if not data then return end
161 | local success = ReQuest("Job Center", 'Are you sure you want to disband the group?', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
162 | if success then
163 | isGroupLeader = false
164 | TriggerServerEvent('rep-tablet:server:DisbandGroup', groupID)
165 | cb("ok")
166 | end
167 | end)
168 | -- Event
169 |
170 | -- Làm mới nhóm, ai đang trong stage sẽ không sửa lại
171 | RegisterNetEvent('rep-tablet:client:RefreshGroupsApp', function(bool)
172 | local job = LocalPlayer.state.nghe
173 | if not job then
174 | SendNUIMessage({
175 | action = "jobcenter",
176 | data = JobCenter,
177 | })
178 | else
179 | if bool then inJob = false end
180 | if inJob then return end
181 | Core.Functions.TriggerCallback('rep-tablet:callback:getGroupsApp', function (bool1, data)
182 | if bool1 then
183 | SendNUIMessage({
184 | action = "addGroupStage", -- Khi set State thì status về true, còn refresh App thì status của job về false. Nếu Stage == {} thì đưa về giao diện các thành viên trong nhóm
185 | status = data, -- cấu trúc của stage https://cdn.discordapp.com/attachments/1036820124784668692/1052217816528461894/image.png
186 | })
187 | else
188 | SendNUIMessage({
189 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
190 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận // Thông tin các nhóm
191 | job = LocalPlayer.state.nghe -- Nghề, lọc ra các nhóm trong bảng data có cùng nghề
192 | })
193 | end
194 | end)
195 | end
196 | end)
197 |
198 | -- Khi mà sign in thì sẽ hiện các ra các nhóm của nghề đó
199 | RegisterNetEvent('rep-tablet:client:signIn', function(bool)
200 | LocalPlayer.state:set('nghe', bool, false)
201 | Core.Functions.TriggerCallback('rep-tablet:callback:getGroupsApp', function (bool, data)
202 | if bool then
203 | else
204 | SendNUIMessage({
205 | action = "refreshApp", --https://cdn.discordapp.com/attachments/1036820124784668692/1052217278701244527/image.png Cấu trúc data gửi lên
206 | data = data, -- nhớ làm lại bảng for để check xem cái nào cùng job thì add và xem cái status nào bận, cái nào không bận
207 | job = LocalPlayer.state.nghe
208 | })
209 | end
210 | end)
211 | end)
212 |
213 | -- Khi mà sign off thì sẽ chuyển lại giao diện jobcenter
214 | RegisterNetEvent('rep-tablet:client:signOff', function()
215 | if groupID ~= 0 or inJob then
216 | if inJob then
217 | SendNUIMessage({
218 | action = "closeAllNotification",
219 | })
220 | end
221 | TriggerServerEvent('rep-tablet:server:checkout', groupID)
222 | LocalPlayer.state:set('nghe', nil, false)
223 | end
224 | if groupID == 0 then
225 | TriggerEvent('rep-tablet:client:checkout')
226 | end
227 | SendNUIMessage({
228 | action = "jobcenter",
229 | data = JobCenter,
230 | })
231 | end)
232 |
233 | -- Add nhiệm vụ
234 | RegisterNetEvent('rep-tablet:client:AddGroupStage', function(data)
235 | inJob = true
236 | SendNUIMessage({
237 | action = "addGroupStage",
238 | status = data
239 | })
240 | end)
241 |
242 | --Set Id cho group
243 | RegisterNetEvent('rep-tablet:client:UpdateGroupId', function(id)
244 | groupID = id
245 | if id == 0 then
246 | isGroupLeader = false
247 | end
248 | end)
249 |
250 | --Xin vào nhóm// Request to join a group
251 | RegisterNetEvent('rep-tablet:client:requestJoinGroup', function(target)
252 | local success = ReQuest("Job Center", target..' want to join your group', 'fas fa-users', '#FFBF00', "NONE", 'bx bxs-check-square', 'bx bxs-x-square')
253 | if success then
254 | TriggerServerEvent('rep-tablet:client:requestJoin', target, true)
255 | else
256 | TriggerServerEvent('rep-tablet:client:requestJoin', target, false)
257 | end
258 | end)
259 |
260 | RegisterNetEvent('rep-tablet:client:notReady', function ()
261 | SendNUIMessage({
262 | action = "cancelReady",
263 | })
264 | end)
265 |
266 | --Update Group Job
267 | RegisterNetEvent('rep-tablet:client:updateGroupJob', function (data)
268 | Config.JobCenter = data
269 | loadConfig()
270 | JobCenter = {}
271 | for k, v in pairs(Config.JobCenter) do
272 | if vpn then
273 | JobCenter[#JobCenter+1] = v
274 | else
275 | if v.vpn == false then
276 | JobCenter[#JobCenter+1] = v
277 | end
278 | end
279 | end
280 | end)
281 |
282 | --Vào nhóm
283 | RegisterNetEvent('rep-tablet:client:Join', function(id)
284 | groupID = id
285 | TriggerServerEvent('rep-tablet:server:Join', id, vpn)
286 | end)
287 |
288 | -- ReQuest
289 | RegisterNetEvent("rep-tablet:client:request", function(title, text, icon, color, timeout, accept, deny)
290 | ReQuest(title, text, icon, color, timeout, accept, deny)
291 | end)
292 |
293 | RegisterNetEvent('rep-tablet:jobcenter:tow', function()
294 | SetNewWaypoint(-238.94, -1183.74)
295 | end)
296 |
297 | RegisterNetEvent('rep-tablet:jobcenter:taxi', function()
298 | SetNewWaypoint(909.51, -177.36)
299 | end)
300 |
301 | RegisterNetEvent('rep-tablet:jobcenter:postop', function()
302 | SetNewWaypoint(-432.51, -2787.98)
303 | end)
304 |
305 | RegisterNetEvent('rep-tablet:jobcenter:sanitation', function()
306 | SetNewWaypoint(-351.44, -1566.37)
307 | end)
308 |
309 | RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
310 | PlayerData = nil
311 | end)
312 |
313 | local function CheckVPN()
314 | for _, itemData in pairs(PlayerData.items) do
315 | if itemData.name == 'vpn' then
316 | return true
317 | end
318 | end
319 | return false
320 | end
321 |
322 | RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
323 | PlayerData = val
324 | Wait(100)
325 | local result = CheckVPN()
326 | if vpn ~= result then
327 | vpn = result
328 | JobCenter = {}
329 | for k, v in pairs(Config.JobCenter) do
330 | if vpn then
331 | JobCenter[#JobCenter+1] = v
332 | else
333 | if v.vpn == false then
334 | JobCenter[#JobCenter+1] = v
335 | end
336 | end
337 | end
338 | TriggerServerEvent('rep-tablet:server:updateVPN', result)
339 | end
340 | end)
341 |
342 | -- Handles state if resource is restarted live.
343 | AddEventHandler('onResourceStart', function(resource)
344 | if GetCurrentResourceName() == resource then
345 | PlayerData = Core.Functions.GetPlayerData()
346 | vpn = CheckVPN()
347 | JobCenter = {}
348 | for k, v in pairs(Config.JobCenter) do
349 | if vpn then
350 | JobCenter[#JobCenter+1] = v
351 | else
352 | if v.vpn == false then
353 | JobCenter[#JobCenter+1] = v
354 | end
355 | end
356 | end
357 | LocalPlayer.state.nghe = nil
358 | end
359 | end)
360 |
361 | AddEventHandler('QBCore:Client:OnPlayerLoaded', function()
362 | Wait(10000)
363 | Core.Functions.TriggerCallback('rep-tablet:callback:getGroupsJob', function (data)
364 | Config.JobCenter = data
365 | end)
366 | vpn = CheckVPN()
367 | loadConfig()
368 | JobCenter = {}
369 | for k, v in pairs(Config.JobCenter) do
370 | if vpn then
371 | JobCenter[#JobCenter+1] = v
372 | else
373 | if v.vpn == false then
374 | JobCenter[#JobCenter+1] = v
375 | end
376 | end
377 | end
378 | PlayerData = Core.Functions.GetPlayerData()
379 | end)
380 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/client/cl_main.lua:
--------------------------------------------------------------------------------
1 | Core = exports['qb-core']:GetCoreObject()
2 | local tabletProp = 0
3 | local tabletModel = joaat("prop_cs_tablet")
4 | local isOpen = false
5 |
6 | local function LoadAnimation(dict)
7 | RequestAnimDict(dict)
8 | while not HasAnimDictLoaded(dict) do
9 | Wait(1)
10 | end
11 | end
12 |
13 | local function deleteTablet()
14 | if tabletProp then
15 | DeleteObject(tabletProp)
16 | tabletProp = 0
17 | end
18 | end
19 |
20 | local function LoopAnim()
21 | CreateThread(function()
22 | local ped = PlayerPedId()
23 | while isOpen do
24 | if not IsEntityPlayingAnim(ped, 'amb@code_human_in_bus_passenger_idles@female@tablet@base', 'base', 3) then
25 | LoadAnimation('amb@code_human_in_bus_passenger_idles@female@tablet@base')
26 | TaskPlayAnim(ped, 'amb@code_human_in_bus_passenger_idles@female@tablet@base', 'base', 8.0, 8.0, -1, 50, 0, false, false, false)
27 | end
28 | Wait(1)
29 | end
30 | ClearPedTasks(ped)
31 | end)
32 | end
33 |
34 | local function Anim()
35 | deleteTablet()
36 | RequestModel(tabletModel)
37 | while not HasModelLoaded(tabletModel) do
38 | Wait(1)
39 | end
40 | local ped = PlayerPedId()
41 | local pos = GetEntityCoords(ped)
42 | tabletProp = CreateObject(tabletModel, pos.x, pos.y, pos.z, 1, 1, 0)
43 | AttachEntityToEntity(tabletProp, ped, GetPedBoneIndex(ped, 60309), 0.03, 0.002, -0.05, 10.0, 160.0, 0.0, 1, 1, 0, 1, 0, 1)
44 | SetModelAsNoLongerNeeded(tabletProp)
45 | SetEntityCompletelyDisableCollision(tabletProp, false, true)
46 | LoopAnim()
47 | end
48 |
49 | local function hasTablet()
50 | if PlayerData.items then
51 | for _, v in pairs(PlayerData.items) do
52 | if v.name == 'tablet' then
53 | return true
54 | end
55 | end
56 | end
57 | end
58 | exports('hasTablet', hasTablet)
59 |
60 | RegisterNUICallback('HasTablet', function(_, cb)
61 | cb(hasTablet())
62 | end)
63 |
64 | local function CustomNotification(title, text, icon, color, timeout)
65 | SendNUIMessage({
66 | action = "CustomNotification",
67 | TabletNotify = {
68 | title = title or "Rep Scripts",
69 | text = text or "MSG",
70 | icon = icon or "fas fa-home",
71 | color = color or "#FFBF00",
72 | timeout = timeout or 1500,
73 | },
74 | })
75 | end
76 |
77 | exports("CustomNotification", CustomNotification)
78 | ---------NUI----------
79 | ---Bật Tablet
80 | local function OpenTablet()
81 | if hasTablet() then
82 | SetNuiFocus(true, true)
83 | SendNUIMessage({
84 | action = "open",
85 | data = PlayerData,
86 | name = PlayerData.charinfo.firstname.." "..PlayerData.charinfo.lastname,
87 | })
88 | isOpen = true
89 | Anim()
90 | else
91 | Core.Functions.Notify("You don't have a tablet?", "error")
92 | end
93 | end
94 |
95 | --Command
96 |
97 | RegisterNetEvent("OpenTabletRep", function()
98 | while not PlayerData do
99 | PlayerData = Core.Functions.GetPlayerData()
100 | Wait(100)
101 | end
102 | if not isOpen then
103 | if not PlayerData.metadata['ishandcuffed'] and not PlayerData.metadata['inlaststand'] and not PlayerData.metadata['isdead'] and not IsPauseMenuActive() then
104 | OpenTablet()
105 | else
106 | Core.Functions.Notify("Action not available at the moment..", "error")
107 | end
108 | end
109 | end)
110 |
111 | RegisterCommand('tablet', function()
112 | TriggerEvent('OpenTabletRep')
113 | end)
114 |
115 | RegisterKeyMapping('tablet', 'Open Tablet', 'keyboard', 'K')
116 |
117 | ---Nui-----
118 | RegisterNUICallback('Close', function()
119 | SetNuiFocus(false, false)
120 | isOpen = false
121 | deleteTablet()
122 | end)
123 |
124 | -- Send a PhoneNotification to the tablet from anywhere
125 | RegisterNetEvent("rep-tablet:client:CustomNotification", function(title, text, icon, color, timeout)
126 | CustomNotification(title, text, icon, color, timeout)
127 | end)
128 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/config.lua:
--------------------------------------------------------------------------------
1 | Config = {}
2 | -- Config thêm job và event chỉ đường vào đây, vpn = true sẽ yêu cầu VPN để hiển thị
3 | Config.JobCenter = {
4 | ['towing'] = {
5 | vpn = false,
6 | label = "Towing",
7 | event = "rep-tablet:jobcenter:tow",
8 | mem = 1, -- Số lượng người tối đa trong 1 nhóm
9 | count = 0, -- Don't touch
10 | salary = 'high',
11 | time = {
12 | first = 2500,
13 | second = 10000,
14 | },
15 | icon = "fas fa-car-crash"
16 |
17 | },
18 | ['taxi'] = {
19 | vpn = false,
20 | label = "Taxi",
21 | event = "rep-tablet:jobcenter:taxi",
22 | mem = 1,
23 | count = 0,
24 | salary = 'mid',
25 | time = {
26 | first = 2500,
27 | second = 10000,
28 | },
29 | icon = "fa-solid fa-taxi"
30 | },
31 | ['chopshop'] = {
32 | vpn = true,
33 | label = "House Robbery",
34 | event = "sn-houserobbery:client:chiduong",
35 | mem = 6,
36 | count = 0,
37 | salary = 'mid',
38 | time = {
39 | first = 2500,
40 | second = 10000,
41 | },
42 | icon = "fa-solid fa-mask"
43 | },
44 | ['oxyrun'] = {
45 | vpn = true,
46 | label = "Oxy Run",
47 | event = "rep-oxyrun:client:chiduong",
48 | mem = 1,
49 | count = 0,
50 | salary = 'mid',
51 | time = {
52 | first = 2500,
53 | second = 10000,
54 | },
55 | icon = "fa-solid fa-pills"
56 | },
57 | ['theftcar'] = {
58 | vpn = true,
59 | label = "Chop Shop",
60 | event = "rep-chopshop:client:chiduong",
61 | mem = 1,
62 | count = 0,
63 | salary = 'mid',
64 | time = {
65 | first = 2500,
66 | second = 10000,
67 | },
68 | icon = "fas fa-lock-open"
69 | },
70 | ['postop'] = {
71 | vpn = false,
72 | label = "PostOp Worker",
73 | event = "rep-tablet:jobcenter:postop",
74 | mem = 2,
75 | count = 0,
76 | salary = 'mid',
77 | time = {
78 | first = 2500,
79 | second = 10000,
80 | },
81 | icon = "fa-solid fa-truck-fast"
82 | },
83 | ['sani'] = {
84 | vpn = false,
85 | label = "Sanitation Worker",
86 | event = "rep-tablet:jobcenter:sanitation",
87 | mem = 4,
88 | count = 0,
89 | salary = 'low',
90 | time = {
91 | first = 2500,
92 | second = 10000,
93 | },
94 | icon = "fas fa-trash"
95 | },
96 | ['taco'] = {
97 | vpn = true,
98 | label = "Taco Shop",
99 | event = "rep-weed:client:chiduong",
100 | mem = 1,
101 | count = 0,
102 | salary = 'mid',
103 | time = {
104 | first = 2500,
105 | second = 10000,
106 | },
107 | icon = "fas fa-cannabis"
108 | },
109 | }
110 |
111 | -- Họ sẽ được random khi trong người có VPN
112 | Config.FirstName = {
113 | 'Trump',
114 | 'Musk',
115 | 'Adams',
116 | 'Harrison',
117 | 'Taft',
118 | 'Long',
119 | 'Lodge',
120 | 'Kennedy',
121 | 'Bayh',
122 | 'Indiana',
123 | 'Brown',
124 | 'Miller',
125 | 'Davis',
126 | 'Garcia',
127 | }
128 | -- Tên sẽ được random khi trong người có VPN
129 | Config.LastName = {
130 | 'James',
131 | 'Robert',
132 | 'John',
133 | 'Michael',
134 | 'Cheng',
135 | 'BahnMy',
136 | 'Cris',
137 | 'Hwan',
138 | 'William'
139 | }
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | fx_version 'cerulean'
2 | game 'gta5'
3 |
4 | name "Rep Dev - Tablet"
5 | author "Q4D#1905 x HWANJR#0928"
6 | version "1.1.2"
7 |
8 | client_scripts {'client/*.lua'}
9 | server_scripts {'server/*.lua'}
10 |
11 | ui_page 'Ui/ui.html'
12 | files {
13 | 'Ui/ui.html',
14 | 'Ui/*.css',
15 | 'Ui/*.js',
16 | 'Ui/imgs/*.png',
17 | 'Ui/imgs/app/*.png',
18 | 'Ui/sounds/*.ogg'
19 | }
20 |
21 | dependencies {
22 | 'ps-ui',
23 | }
24 |
25 | shared_script 'config.lua'
26 | lua54 'yes'
27 |
--------------------------------------------------------------------------------
/qb-core ver/rep-tablet/server/sv_group.lua:
--------------------------------------------------------------------------------
1 | Core = exports['qb-core']:GetCoreObject()
2 |
3 | local Players = {} -- Don't Touch if you don't know
4 | local Groups = {}
5 | -- Lấy tên của người chơi
6 | local function GetPlayerCharName(src)
7 | local player = Core.Functions.GetPlayer(src)
8 | return player.PlayerData.charinfo.firstname.." "..player.PlayerData.charinfo.lastname
9 | end
10 |
11 | Core.Functions.CreateUseableItem("tablet",function(source)
12 | TriggerClientEvent('OpenTabletRep', source)
13 | end)
14 |
15 | -- Random Name khi có VPN
16 | local function RandomName()
17 | local random1 = math.random(1, #Config.FirstName)
18 | local random2 = math.random(1, #Config.LastName)
19 | return Config.FirstName[random1].." "..Config.LastName[random2]
20 | end
21 |
22 | -- Gửi thông báo cho tất cả thành viên trong nhóm // Thay đổi loại thông báo tuỳ server
23 | local function NotifyGroup(group, msg, type, time)
24 | if not group or not Groups[group] then return print("Group not found...") end
25 | for _, v in pairs(Groups[group].members) do
26 | TriggerClientEvent('QBCore:Notify', v.player, msg or "NO MSG", type or 'primary', time or 7500)
27 | end
28 | end
29 |
30 | exports("NotifyGroup", NotifyGroup)
31 |
32 | -- Gửi thông báo Custom của điện thoại cho tất cả thành viên trong nhóm
33 | local function pNotifyGroup(group, header, msg, icon, colour, length)
34 | if not group or not Groups[group] then return print("Group not found...") end
35 | for _, v in pairs(Groups[group].members) do
36 | TriggerClientEvent('rep-tablet:client:CustomNotification', v.player,
37 | header or "NO HEADER",
38 | msg or "NO MSG",
39 | icon or "fas fa-phone-square",
40 | colour or "#e84118",
41 | length or 7500
42 | )
43 | end
44 | end
45 |
46 | exports("pNotifyGroup", pNotifyGroup)
47 |
48 | --Lấy Group bằng members
49 | local function getGroup(src)
50 | if not Players[src] then return nil end
51 | for group, _ in pairs(Groups) do
52 | for _, v in pairs (Groups[group].members) do
53 | if v.player == src then
54 | return Groups[group]
55 | end
56 | end
57 | end
58 | return nil
59 | end
60 |
61 | exports("getGroup", getGroup)
62 |
63 | --Lấy Id của group bằng members
64 | local function getGroupByMembers(src)
65 | if not Players[src] then return nil end
66 | for group, _ in pairs(Groups) do
67 | for _, v in pairs (Groups[group].members) do
68 | if v.player == src then
69 | return group
70 | end
71 | end
72 | end
73 | return nil
74 | end
75 |
76 | exports("getGroupByMembers", getGroupByMembers)
77 |
78 | -- Lấy id của các member trong group bằng id của group
79 | local function getGroupMembers(id)
80 | if not id then return print("Id not found") end
81 | if not Groups[id] then return print("Group :"..id.." not found") end
82 | local temp = {}
83 | for _,v in pairs(Groups[id].members) do
84 | temp[#temp+1] = v.player
85 | end
86 | return temp
87 | end
88 |
89 | exports('getGroupMembers', getGroupMembers)
90 |
91 | -- Lấy số lượng thành viên trong nhóm
92 | local function getGroupSize(id)
93 | if not id then return print("Id not found") end
94 | if not Groups[id] then return print("Group :"..id.." not found") end
95 | return Groups[id].users
96 | end
97 |
98 | exports('getGroupSize', getGroupSize)
99 |
100 | -- Lấy id của trường nhóm bằng id của nhóm
101 | local function GetGroupLeader(id)
102 | if not id then return print("Id not found") end
103 | if Groups[id] == nil then
104 | return nil
105 | end
106 | return Groups[id].leader
107 | end
108 |
109 | exports("GetGroupLeader", GetGroupLeader)
110 |
111 | -- Trigger event cho các thành viên trong group
112 | function GroupEvent(id, event, args)
113 | if not id then return print("Id not found") end
114 | if not Groups[id] then return print("Group :"..id.." not found") end
115 | if not event then return print("no valid event was passed to GroupEvent") end
116 | local members = getGroupMembers(id)
117 | if members and #members > 0 then
118 | for i = 1, #members do
119 | if members[i] then
120 | if args ~= nil then
121 | TriggerClientEvent(event, members[i], table.unpack(args))
122 | else
123 | TriggerClientEvent(event, members[i])
124 | end
125 | end
126 | end
127 | end
128 | end
129 |
130 | exports("GroupEvent", GroupEvent)
131 |
132 | -- Kiểm tra xem có phải trưởng nhóm hay không
133 | local function isGroupLeader(src, id)
134 | if not id then return end
135 | local grouplead = GetGroupLeader(id)
136 | return grouplead == src or false
137 | end
138 |
139 | exports('isGroupLeader', isGroupLeader)
140 |
141 | ---- Set nhiệm vụ cho nhóm
142 | local function setJobStatus(id, stages)
143 | if not id then return print("Id not found") end
144 | if not Groups[id] then return print("Group :"..id.." not found") end
145 | Groups[id].status = true
146 | Groups[id].stage = stages or {}
147 | local m = getGroupMembers(id)
148 | if not m then return end
149 | for i=1, #m do
150 | if m[i] then
151 | TriggerClientEvent("rep-tablet:client:AddGroupStage", m[i], Groups[id])
152 | end
153 | end
154 | end
155 | exports('setJobStatus', setJobStatus)
156 |
157 | -- Đổi trưởng nhóm
158 | local function ChangeGroupLeader(id)
159 | if not id then return print("Id not found") end
160 | if not Groups[id] then return print("Group :"..id.." not found") end
161 | local members = Groups[id].members
162 | local leader = GetGroupLeader(id)
163 | if #members > 1 then
164 | for i=1, #members do
165 | if members[i].player ~= leader then
166 | Groups[id].leader = members[i].player
167 | Groups[id].gName = members[i].name
168 | TriggerClientEvent('QBCore:Notify', members[i].player, "You have become the group leader", "success")
169 | return true
170 | end
171 | end
172 | end
173 | return false
174 | end
175 |
176 | -- Reset Stage của nhóm về không
177 | local function resetJobStatus(id)
178 | if not id then return print("Id not found") end
179 | if not Groups[id] then return print("Group :"..id.." not found") end
180 | Groups[id].status = false
181 | Groups[id].stage = {}
182 | local m = getGroupMembers(id)
183 | if not m then return end
184 | for i=1, #m do
185 | if m[i] then
186 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
187 | end
188 | end
189 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
190 | end
191 |
192 | exports('resetJobStatus', resetJobStatus)
193 |
194 | -- Xoá nhóm
195 | local function DestroyGroup(id)
196 | if not id then return print("Id not found") end
197 | if not Groups[id] then return print("Group :"..id.." not found") end
198 | local members = getGroupMembers(id)
199 | if members and #members > 0 then
200 | for i = 1, #members do
201 | if members[i] then
202 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', members[i], 0)
203 | TriggerClientEvent('rep-tablet:client:checkout', members[i])
204 | TriggerClientEvent('rep-tablet:client:closeAllNotification', members[i])
205 | Wait(100)
206 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', members[i], true)
207 | Players[members[i]] = false
208 | end
209 | end
210 | end
211 | if Config.JobCenter[Groups[id].job] then
212 | Config.JobCenter[Groups[id].job].count = Config.JobCenter[Groups[id].job].count - 1
213 | end
214 | TriggerClientEvent('rep-tablet:client:updateGroupJob', -1, Config.JobCenter)
215 | Groups[id] = nil
216 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
217 | end
218 |
219 | exports("DestroyGroup", DestroyGroup)
220 |
221 | -- Đuổi người chơi khỏi nhóm
222 | local function RemovePlayerFromGroup(src, id, disconnected)
223 | if not Players[src] then return false end
224 | if not id then return print("Id not found") end
225 | if not Groups[id] then return print("Group :"..id.." not found") end
226 | local g = Groups[id].members
227 | for k,v in pairs(g) do
228 | if v.player == src then
229 | table.remove(Groups[id].members, k)
230 | Groups[id].users = Groups[id].users - 1
231 | Players[src] = false
232 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', src, 0)
233 | pNotifyGroup(id, "Job Center", src.." has left the group", "fas fa-users", "#FFBF00", 7500)
234 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', src, true)
235 | if disconnected then
236 | TriggerClientEvent("QBCore:Notify", src, "You have left the group", "error")
237 | TriggerClientEvent('rep-tablet:client:checkout', src)
238 | else
239 | TriggerClientEvent("QBCore:Notify", src, "You have left the group", "error")
240 | end
241 | if Groups[id].users <= 0 then
242 | DestroyGroup(id)
243 | else
244 | local m = getGroupMembers(id)
245 | if not m then return end
246 | for i=1, #m do
247 | if m[i] then
248 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
249 | end
250 | end
251 | end
252 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
253 | return
254 | end
255 | end
256 | end
257 |
258 | ----EVENT-----
259 | --Tạo nhóm
260 | RegisterNetEvent("rep-tablet:server:createJobGroup", function(bool, job)
261 | local src = source
262 | local player = Core.Functions.GetPlayer(src)
263 | if Players[src] then TriggerClientEvent('QBCore:Notify', src, "You have already created a group", "error") return end
264 | Players[src] = true
265 | local ID = #Groups+1
266 | local name
267 | if bool then
268 | name = RandomName()
269 | else
270 | name = GetPlayerCharName(src)
271 | end
272 | Groups[ID] = {
273 | id = ID,
274 | status = false,
275 | job = job,
276 | gName = name,
277 | users = 1,
278 | leader = src,
279 | members = {
280 | {name = name, cid = player.PlayerData.citizenid, player = src, vpn = bool}
281 | },
282 | stage = {},
283 | }
284 | if Config.JobCenter[job] then
285 | Config.JobCenter[job].count = Config.JobCenter[job].count + 1
286 | else
287 | Config.JobCenter[job].count = 1
288 | end
289 | TriggerClientEvent('rep-tablet:client:updateGroupJob', -1, Config.JobCenter)
290 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
291 | TriggerClientEvent('rep-tablet:client:UpdateGroupId', src, ID)
292 | TriggerClientEvent('rep-tablet:client:AddGroupStage', src, Groups[ID])
293 | end)
294 |
295 | RegisterNetEvent("rep-tablet:server:updateVPN", function (result)
296 | local src = source
297 | if Players[src] then
298 | local id = getGroupByMembers(src)
299 | local leader = isGroupLeader(src, id)
300 | if result then
301 | local name = RandomName()
302 | if leader then
303 | Groups[id].gName = name
304 | end
305 | for _, v in pairs (Groups[id].members) do
306 | if v.player == src then
307 | Groups[id].members[_].name = name
308 | Groups[id].members[_].vpn = true
309 | end
310 | end
311 | else
312 | local name = GetPlayerCharName(src)
313 | if leader then
314 | Groups[id].gName = name
315 | end
316 | for _, v in pairs (Groups[id].members) do
317 | if v.player == src then
318 | Groups[id].members[_].name = name
319 | Groups[id].members[_].vpn = false
320 | end
321 | end
322 | end
323 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
324 | local m = getGroupMembers(id)
325 | if not m then return end
326 | for i=1, #m do
327 | if m[i] then
328 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
329 | end
330 | end
331 | end
332 | end)
333 |
334 | RegisterNetEvent('rep-tablet:server:requestJoinGroup', function(data)
335 | local src = source
336 | if Players[src] then return TriggerClientEvent("QBCore:Notify", src, "You are already a part of a group", "error") end
337 | if not data.id then
338 | return
339 | end
340 | if not Groups[data.id] then return TriggerClientEvent("QBCore:Notify", src, "That group doesn't exist", "error") end
341 | local leader = GetGroupLeader(data.id)
342 | TriggerClientEvent('rep-tablet:client:requestJoinGroup', leader, src)
343 | end)
344 |
345 | RegisterNetEvent('rep-tablet:client:requestJoin', function(target, bool)
346 | local src = source
347 | if not Groups[getGroupByMembers(src)] then return TriggerClientEvent("QBCore:Notify", target, "That group doesn't exist", "error") end
348 | if Groups[getGroupByMembers(src)].status == true then
349 | TriggerClientEvent("QBCore:Notify", target, "This group is already working", "error")
350 | return
351 | end
352 | if bool then
353 | if getGroupSize(getGroupByMembers(src)) < 6 then
354 | TriggerClientEvent('rep-tablet:client:Join', target, getGroupByMembers(src))
355 | else
356 | TriggerClientEvent("QBCore:Notify", target, getGroupByMembers(src).." is full", "error")
357 | TriggerClientEvent("QBCore:Notify", src, "Cannot recruit more people into the team", "error")
358 | end
359 | else
360 | TriggerClientEvent("QBCore:Notify", target, "The group leader "..getGroupByMembers(src).." has rejected you", "error")
361 | end
362 | end)
363 |
364 | RegisterNetEvent('rep-tablet:server:Join', function (id, vpn)
365 | local src = source
366 | local player = Core.Functions.GetPlayer(src)
367 | if Players[src] then return TriggerClientEvent('QBCore:Notify', src, "You are already a part of a group!", "success") end
368 | if not id then
369 | return
370 | end
371 | if not Groups[id] then return TriggerClientEvent("QBCore:Notify", src, "That group doesn't exist", "error") end
372 | if Groups[id].status == true then
373 | TriggerClientEvent("QBCore:Notify", src, "This group is already working", "error")
374 | return
375 | end
376 | local name
377 | if vpn then
378 | name = RandomName()
379 | else
380 | name = GetPlayerCharName(src)
381 | end
382 | pNotifyGroup(id, "Job Center", src.." has join the group", "fas fa-users", "#FFBF00", 7500)
383 | Groups[id].members[#Groups[id].members+1] = {name = name, cid = player.PlayerData.citizenid, player = src, vpn = vpn}
384 | Groups[id].users = Groups[id].users + 1
385 | Players[src] = true
386 | local m = getGroupMembers(id)
387 | if not m then return end
388 | for i=1, #m do
389 | if m[i] then
390 | TriggerClientEvent('rep-tablet:client:AddGroupStage', m[i], Groups[id])
391 | end
392 | end
393 | TriggerClientEvent('QBCore:Notify', src, "You joined the group "..id, "success")
394 | TriggerClientEvent('rep-tablet:client:RefreshGroupsApp', -1)
395 | TriggerClientEvent('rep-tablet:client:JoinSuccess',src)
396 | end)
397 |
398 | RegisterNetEvent('rep-tablet:server:LeaveGroup', function(id)
399 | local src = source
400 | if not id then
401 | return
402 | end
403 | if not Players[src] then return end
404 | if isGroupLeader(src, id) then
405 | local change = ChangeGroupLeader(id)
406 | if change then
407 | RemovePlayerFromGroup(src, id)
408 | else
409 | DestroyGroup(id)
410 | end
411 | else
412 | RemovePlayerFromGroup(src, id)
413 | end
414 | end)
415 |
416 | RegisterNetEvent('rep-tablet:server:DisbandGroup', function(id)
417 | local src = source
418 | if not Players[src] then return end
419 | DestroyGroup(id)
420 | end)
421 |
422 | RegisterNetEvent('rep-tablet:server:checkout', function(id)
423 | local src = source
424 | if not Players[src] then return end
425 | if isGroupLeader(src, id) then
426 | if Groups[id].status == true then
427 | DestroyGroup(id)
428 | else
429 | local change = ChangeGroupLeader(id)
430 | if change then
431 | RemovePlayerFromGroup(src, id, true)
432 | else
433 | DestroyGroup(id)
434 | end
435 | end
436 | else
437 | RemovePlayerFromGroup(src,id, true)
438 | end
439 | end)
440 |
441 | Core.Functions.CreateCallback('rep-tablet:callback:getGroupsApp', function(source, cb)
442 | local src = source
443 | if Players[src] then
444 | local id = getGroupByMembers(src)
445 | cb(true, Groups[id])
446 | else
447 | cb(false, Groups)
448 | end
449 | end)
450 |
451 | Core.Functions.CreateCallback('rep-tablet:callback:getGroupsJob', function(source, cb)
452 | cb(Config.JobCenter)
453 | end)
454 |
455 | Core.Functions.CreateCallback('rep-tablet:callback:CheckPlayerNames', function(source, cb, id)
456 | local src = source
457 | if Groups[id] == nil then
458 | TriggerClientEvent("QBCore:Notify", src, "That group doesn't exist", "error")
459 | cb(false)
460 | end
461 | cb(Groups[id].members)
462 | end)
463 |
464 | Core.Functions.CreateCallback('rep-tablet:callback:getDataGroup', function(_, cb)
465 | cb(Groups)
466 | end)
467 |
468 | AddEventHandler('playerDropped', function()
469 | local src = source
470 | local id = getGroupByMembers(src)
471 | if id then
472 | if isGroupLeader(src, id) then
473 | if Groups[id].status == true then
474 | DestroyGroup(id)
475 | else
476 | local change = ChangeGroupLeader(id)
477 | if change then
478 | RemovePlayerFromGroup(src, id, true)
479 | else
480 | DestroyGroup(id)
481 | end
482 | end
483 | else
484 | RemovePlayerFromGroup(src, id, true)
485 | end
486 | end
487 | end)
488 |
--------------------------------------------------------------------------------