Advertisement
FlameFloodv

client (LocalScript)

Dec 24th, 2024
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.86 KB | None | 0 0
  1. -- declaring variables: services, the player itself, gui elements, debounce and remote functions
  2. local players = game:GetService('Players')
  3. local replicatedStorage = game:GetService('ReplicatedStorage')
  4.  
  5. local player = players.LocalPlayer
  6. local mouse = player:GetMouse()
  7.  
  8. -- gui elements
  9. local gui = player.PlayerGui:WaitForChild('ScreenGui')
  10. local menu = gui:WaitForChild('menu')
  11. local new = gui:WaitForChild('new')
  12. local view = gui:WaitForChild('view')
  13. local modify = gui:WaitForChild('modify')
  14. local loadingImage = gui:WaitForChild('loading')
  15.  
  16. local mDataFrame = modify.DataFrame
  17. local vDataFrame = view.DataFrame
  18.  
  19. -- debounces
  20. local debounces = {}
  21.  
  22. -- remote functions
  23. local sendRemote = replicatedStorage.sendSuggestion
  24. local viewRemote = replicatedStorage.viewSuggestions
  25. local viewAllRemote = replicatedStorage.viewAllSuggestions
  26. local modifyRemote = replicatedStorage.modifySuggestion
  27.  
  28. --[[loading function:
  29.  on function initiation, creates a loading image that follows the mouse around and returns the image itself
  30.  the initiator can later on delete the image that was returned in order to stop the loading
  31. ]]
  32. local function newLoad()
  33.     local image = loadingImage:Clone()
  34.     image.Parent = gui
  35.  
  36.     task.spawn(function()
  37.         while task.wait() do
  38.             if not image then
  39.                 break
  40.             end
  41.  
  42.             image.Rotation += 2
  43.             image.Position = UDim2.new(0, mouse.X, 0, mouse.Y)
  44.         end
  45.     end)
  46.  
  47.     return image
  48. end
  49.  
  50. --functionality of gui buttons: switch between frames (menu/view/new/modify), return to the menu from any
  51. --subframe
  52. local function switch(from, to)
  53.     from.Visible = false
  54.     to.Visible = true
  55. end
  56.  
  57. menu.new.MouseButton1Click:Connect(function()
  58.     switch(menu, new)
  59. end)
  60. menu.view.MouseButton1Click:Connect(function()
  61.     switch(menu, view)
  62. end)
  63. menu.modify.MouseButton1Click:Connect(function()
  64.     switch(menu, modify)
  65. end)
  66.  
  67. new.back.MouseButton1Click:Connect(function()
  68.     switch(new, menu)
  69. end)
  70. view.back.MouseButton1Click:Connect(function()
  71.     switch(view, menu)
  72. end)
  73. modify.back.MouseButton1Click:Connect(function()
  74.     switch(modify, menu)
  75. end)
  76.  
  77. vDataFrame.back.MouseButton1Click:Connect(function()
  78.     switch(vDataFrame, view.ScrollingFrame)
  79. end)
  80. mDataFrame.back.MouseButton1Click:Connect(function()
  81.     switch(mDataFrame, modify.ScrollingFrame)
  82. end)
  83.  
  84. -- send suggestion functionality
  85. local function validateTextInput(text)
  86.     --[[
  87.     ensure that the text is not empty or exceeds the character limit. if the text's length is less than 10,
  88.     return false and changes the text's color. if the text's length exceeds 512, return false either
  89.     otherwise, return true
  90.     providing clear and immediate feedback on validation results enhances usability by allowing users to quickly
  91.     understand and correct issues with their input
  92.     --]]
  93.     if #text < 10 then
  94.         new.note.Text = "Text is too short!"
  95.         new.note.TextColor3 = Color3.new(1, 0, 0)
  96.         return false
  97.     elseif #text > 512 then
  98.         new.note.Text = "Text is too long!"
  99.         new.note.TextColor3 = Color3.new(1, 0, 0)
  100.         return false
  101.     end
  102.     return true
  103. end
  104.  
  105. -- function to handle the response after suggestion submission
  106. local function handleSuggestionResponse(response)
  107.     --[[
  108.     handle the server's response after submitting a suggestion
  109.     1. display success or failure message
  110.     2. reset the textbox and button after a delay of 60 seconds (aka debounce)
  111.     visual feedback ensures users are informed about the outcome of their submission, reinforcing trust
  112.     in the system and the delay prevents spamming and preserves server integrity
  113.     --]]
  114.     if response.success then
  115.         new.note.Text = "Suggestion submitted successfully!"
  116.         new.note.TextColor3 = Color3.new(0, 1, 0)
  117.     else
  118.         new.note.Text = "Failed to submit suggestion!"
  119.         new.note.TextColor3 = Color3.new(1, 0, 0)
  120.     end
  121.     task.wait(60)
  122.     new.write.Interactable = true
  123. end
  124.  
  125. new.send.MouseButton1Click:Connect(function()
  126.     -- a debounce and text input validation checks, to avoid spam clicks and invalid text
  127.     if not validateTextInput(new.write.Text) then
  128.         return
  129.     end
  130.  
  131.     if debounces['sendDebounce'] then
  132.         return
  133.     end
  134.     debounces.sendDebounce = true
  135.  
  136.     --[[
  137.     sends suggestions to the server and returns whether it was successful or not
  138.    
  139.     main functionality:
  140.     1. send a request to the server with the text from the textbox
  141.     2. store the server's response and reflect the success or failure visually on note's text color
  142.     3. disable the send button while processing the request
  143.     4. display the server's response briefly, then reset the gui elements
  144.     providing visual cues, such as disabling the button, prevents user confusion and unintentional duplicate
  145.     submissions
  146.     --]]
  147.     local image = newLoad()
  148.     local response = sendRemote:InvokeServer(new.write.Text)
  149.  
  150.     image:Destroy()
  151.     handleSuggestionResponse(response)
  152.  
  153.     debounces.sendDebounce = nil
  154. end)
  155.  
  156. -- dynamically updating text length status in the textbox
  157. new.write:GetPropertyChangedSignal('Text'):Connect(function()
  158.     --[[
  159.     updates the note's text to show the number of characters entered so far,
  160.     and changes color based on length validation
  161.     by dynamically showing the text length, users receive immediate feedback, helping them stay within limits
  162.     without trial and error
  163.     --]]
  164.     new.note.Text = #new.write.Text..'/512' -- displays text length
  165.     new.note.TextColor3 = (#new.write.Text < 512 and #new.write.Text > 10) and Color3.new(0, 1) or Color3.new(1)
  166. end)
  167.  
  168. local function updateStatus(statusLabel, status)
  169.     --[[
  170.     update the visual status of suggestions
  171.     status labels' color changes depending on the "status" variable:
  172.      0 - in view (yellow)
  173.      1 - approved (green)
  174.      2 - rejected (red)
  175.     visually distinguishing statuses with colors simplifies understanding for users at a glance, improving
  176.     accessibility and clarity
  177.     --]]
  178.     statusLabel.TextColor3 =
  179.         status == 0 and Color3.new(1, 1)
  180.         or status == 1 and Color3.new(0, 1)
  181.         or Color3.new(1)
  182.     statusLabel.Text =
  183.         status == 0 and 'In view'
  184.         or status == 1 and 'Approved'
  185.         or 'Rejected'
  186. end
  187.  
  188. local function updateViewList()
  189.     --[[
  190.     shows a list of your suggestions with its details including: text, status, # of the suggestion
  191.    
  192.     functionality:
  193.     1. clear previous content in the scrolling frame
  194.     2. fetch suggestions from the server
  195.     3. if successful, populate the frame with buttons for each suggestion
  196.     4. clicking a button reveals detailed data about the suggestion
  197.     this systematic approach ensures users can navigate and interact with their data intuitively, even when
  198.     the list grows large
  199.     --]]
  200.  
  201.     for _, frame in next, view.ScrollingFrame:GetChildren() do
  202.         if frame.Name ~= 'UIGridLayout' and frame.Name ~= 'template' then
  203.             frame:Destroy()
  204.         end
  205.     end
  206.  
  207.     local response = viewRemote:InvokeServer()
  208.  
  209.     if not response then
  210.         return
  211.     end
  212.  
  213.     for id, data in next, response do
  214.         local template = view.ScrollingFrame.template:Clone()
  215.         template.Parent = view.ScrollingFrame
  216.         template.Visible = true
  217.         template.Name = id
  218.         template.suggestion.Text = string.format('Suggestion #%s', id)
  219.         template.suggestion.TextColor3 =
  220.             data.status == 0 and Color3.new(1, 1)
  221.             or data.status == 1 and Color3.new(0, 1)
  222.             or Color3.new(1)
  223.  
  224.         template.suggestion.MouseButton1Click:Connect(function()
  225.             vDataFrame.text.Text = data.text
  226.             vDataFrame.TextLabel.Text = string.format('Suggestion #%s', id)
  227.             updateStatus(vDataFrame.status, data.status)
  228.  
  229.             vDataFrame.Visible = true
  230.             view.ScrollingFrame.Visible = false
  231.         end)
  232.     end
  233. end
  234.  
  235. updateViewList()
  236.  
  237. local function updateModifyList()
  238.     --[[
  239.     functionality is identical to updateViewList, but includes player-specific data, showing
  240.     which player made the suggestion.
  241.     including player details ensures moderators can manage and review suggestions more effectively, increasing
  242.     accountability
  243.     --]]
  244.  
  245.     for _, frame in next, modify.ScrollingFrame:GetChildren() do
  246.         if frame.Name ~= 'UIGridLayout' and frame.Name ~= 'template' then
  247.             frame:Destroy()
  248.         end
  249.     end
  250.  
  251.     local response = viewAllRemote:InvokeServer()
  252.  
  253.     if not response then
  254.         return
  255.     end
  256.  
  257.     for playerId, playerData in next, response do
  258.         local playerName = players:GetNameFromUserIdAsync(playerId)
  259.         for id, data in next, playerData do
  260.             local template = modify.ScrollingFrame.template:Clone()
  261.             template.Parent = modify.ScrollingFrame
  262.             template.Visible = true
  263.             template.Name = id
  264.             template.suggestion.Text = string.format(`Suggestion #%s (by @%s)`, id, playerName)
  265.             template.suggestion.TextColor3 =
  266.                 data.status == 0 and Color3.new(1, 1)
  267.                 or data.status == 1 and Color3.new(0, 1)
  268.                 or Color3.new(1)
  269.  
  270.             template.suggestion.MouseButton1Click:Connect(function()
  271.                 mDataFrame.text.Text = data.text
  272.                 mDataFrame.TextLabel.Text = string.format('Suggestion #%s (by @%s)', id, playerName)
  273.  
  274.                 updateStatus(mDataFrame.status, data.status)
  275.  
  276.                 mDataFrame.status.MouseButton1Click:Connect(function()
  277.                     if debounces['statusDebounce'] then
  278.                         return
  279.                     end
  280.  
  281.                     debounces.statusDebounce = true
  282.  
  283.                     --[[
  284.                     the status cycle represents the different states of a suggestion:
  285.                      0: in view (no decision has been made)
  286.                      1: accepted (the suggestion has been accepted)
  287.                      2: rejected (the suggestion has been rejected)
  288.                      the status is incremented each time, and after reaching 2, it wraps back to 0
  289.                      providing this cyclic behavior allows for easier toggling between states, simplifying
  290.                      moderation
  291.                     --]]
  292.                     local image = newLoad()
  293.                     local newStatus = (data.status + 1) % 3
  294.                     local response = modifyRemote:InvokeServer(playerId, id, newStatus)
  295.  
  296.                     image:Destroy()
  297.                     debounces.statusDebounce = nil
  298.  
  299.                     if not response then
  300.                         return
  301.                     end
  302.  
  303.                     data.status = response
  304.  
  305.                     updateStatus(mDataFrame.status, response)
  306.                     template.suggestion.TextColor3 =
  307.                         response == 0 and Color3.new(1, 1)
  308.                         or response == 1 and Color3.new(0, 1)
  309.                         or Color3.new(1)
  310.                 end)
  311.  
  312.                 mDataFrame.Visible = true
  313.                 modify.ScrollingFrame.Visible = false
  314.             end)
  315.         end
  316.     end
  317. end
  318.  
  319. updateModifyList()
  320.  
  321. local function updateButton(update, name)
  322.     --[[
  323.     add functionality to the update buttons
  324.     1. initiate the corresponding update function (updateViewList or updateModifyList)
  325.     2. rotate the button while the update is in progress
  326.     3. prevent multiple simultaneous updates using debounces
  327.     this visual rotation effect reinforces that an update is ongoing, reducing user uncertainty during longer
  328.     operations
  329.     --]]
  330.     update.MouseButton1Click:Connect(function()
  331.         if debounces[name] then
  332.             return
  333.         end
  334.         debounces[name] = true
  335.  
  336.         local respondReceived = false
  337.         coroutine.wrap(function()
  338.             repeat
  339.                 gui[name].update.Rotation += 2
  340.                 task.wait()
  341.             until respondReceived
  342.             gui[name].update.Rotation = 0
  343.         end)()
  344.         local image = newLoad()
  345.  
  346.         if name == 'view' then
  347.             updateViewList()
  348.         else
  349.             updateModifyList()
  350.         end
  351.  
  352.         image:Destroy()
  353.         respondReceived = true
  354.  
  355.         task.wait(3)
  356.         debounces[name] = false
  357.     end)
  358. end
  359.  
  360. updateButton(view.update, 'view')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement