├── 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 | '' 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(''); 227 | } else { 228 | $("#room-actions").html( 229 | '' + 233 | '' 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 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |

Welcome, Hwan Dep Trai

49 |
50 |
51 |

Friday, 04/11/2022

52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 |

100%

60 |
61 |
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 |
99 |
100 |
101 |
102 | 103 |

job center

104 |
105 |
106 | 111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 122 |

rep group

123 |
124 |
125 | 129 | 133 |
134 |
135 |
136 |

groups are idle

137 |
138 |

groups are busy

139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | 149 |

your room

150 |
151 |
152 |
153 |
154 |

members list

155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | 165 |

group tasks

166 |
167 |
168 |

Time: 00:00:00

169 |
170 |
171 |
172 |
173 |
174 |

Task Information

175 | 176 |

177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 | 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 | '' 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(''); 227 | } else { 228 | $("#room-actions").html( 229 | '' + 233 | '' 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 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |

Welcome, Hwan Dep Trai

49 |
50 |
51 |

Friday, 04/11/2022

52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 |

100%

60 |
61 |
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 |
99 |
100 |
101 |
102 | 103 |

job center

104 |
105 |
106 | 111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | 122 |

rep group

123 |
124 |
125 | 129 | 133 |
134 |
135 |
136 |

groups are idle

137 |
138 |

groups are busy

139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | 149 |

your room

150 |
151 |
152 |
153 |
154 |

members list

155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | 165 |

group tasks

166 |
167 |
168 |

Time: 00:00:00

169 |
170 |
171 |
172 |
173 |
174 |

Task Information

175 | 176 |

177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 | 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 | --------------------------------------------------------------------------------