[Need Feedback] Time DataStore script

[English is not my main language so I am sorry if there are any grammatical mistakes]
So I am making a sandbox-style farming game. In this case, there’s an item named ‘Farmland’ which is used to harvest crops. So I wanted to make it so that whenever a player leaves the game, the harvesting continues. There’s a module script which has the crop information used by a script which makes a datastore in which it saves the current time and when it is supposed to be completed. I have made a system where it creates an Id which is then used to the data store. I wanted to know if I could optimise the code by any means or make any little improvements at all

--Module script
local cropInfo = {}

local crops = {
	["Wheat"] = {
		["Time"] = .12; -- 120 seconds
		["Crop"] = "Wheat";
		["CostInCash"] = 15;
		["CostInCoin"] = 0
	}
	
}

cropInfo.ReturnCrop = function(cropName)
	local cropInfo = crops[cropName]
	
	return cropInfo
end

return cropInfo

//////////////////////////////////////////////////

-- Main script
local DataStore = game:GetService("DataStoreService")

local ItemIdDS = DataStore:GetDataStore("ItemId")

local ItemFnDS = DataStore:GetDataStore("ItemFunctions")

local Event = game.ReplicatedStorage.Events.HarvestingTriggered

local cropModule = require(game.ReplicatedStorage.Modules.Crops)

Event.OnServerEvent:Connect(function(Player, Item, CropName, Cost, Currency)
	if Item == script.Parent then
		if Currency == "Money" then
			Player.mainFolder.Money.Value = Player.mainFolder.Money.Value - Cost
		else
			Player.mainFolder.Coins.Value = Player.mainFolder.Coins.Value - Cost
		end
		
		local playerKey = Player.UserId
		local cropInfo = cropModule.ReturnCrop(CropName)
		
		if cropInfo then
			local timeWait = cropInfo["Time"]
			local ItemId = ItemIdDS:IncrementAsync(playerKey .. script.Parent.Name, 1) -- script.Parent.Name means item's name so the Id is given for every individual item
			
			local CurrentTime = os.time()
			
			local itemTable = {
				
				["timeWait"] = timeWait
				["currentTime"] = CurrentTime
				["Crop"] = CropName
				
			}
			
			local success, err = pcall(function()
				ItemFnDS:SetAsync(playerKey .. script.Parent.Name .. tostring(ItemId), itemTable)
			end)
			
			if not success then
				warn("Unable to save data " .. err)
			end
			
			script.Parent.ItemProperties.ItemId.Value = ItemId -- when a player leaves their itemId gets saved in this
		end
	end
	
end)

local function PerformItemFunction(time, timeWait, cropName)
	local currentTime = os.time()
	
	while true do
		wait()
		if (time - currentTime)/3600 >= timeWait then
			for i,v in pairs (script.Parent:GetChildren()) do
				if v.Name == "plot" then
					local crop = v:FindFirstChild(cropName .. "5") -- this means the stage of crop, just a cosmetic
					local crop2 = v:FindFirstChild(cropName .. "4")
					for i,v in pairs (crop:GetChildren()) do
						v.Transparency = 0
					end
					for i,v in pairs (crop2:GetChildren()) do
						v.Transparency = 1
					end
					break -- break, then script determines if the process is finished or not
				end
			end
		elseif (time - currentTime)/3600 >= timeWait/4 then
			for i,v in pairs (script.Parent:GetChildren()) do
				if v.Name == "plot" then
					local crop = v:FindFirstChild(cropName .. "2")
					local crop2 = v:FindFirstChild(cropName .. "1")
					for i,v in pairs (crop:GetChildren()) do
						v.Transparency = 0
					end
					for i,v in pairs (crop2:GetChildren()) do
						v.Transparency = 1
					end
				end
			end
		elseif (time - currentTime)/3600 >= timeWait/3 then
			for i,v in pairs (script.Parent:GetChildren()) do
				if v.Name == "plot" then
					local crop = v:FindFirstChild(cropName .. "3")
					local crop2 = v:FindFirstChild(cropName .. "2")
					for i,v in pairs (crop:GetChildren()) do
						v.Transparency = 0
					end
					for i,v in pairs (crop2:GetChildren()) do
						v.Transparency = 1
					end
				end
			end
		elseif (time - currentTime)/3600 >= timeWait/2 then
			for i,v in pairs (script.Parent:GetChildren()) do
				if v.Name == "plot" then
					local crop = v:FindFirstChild(cropName .. "4")
					local crop2 = v:FindFirstChild(cropName .. "3")
					for i,v in pairs (crop:GetChildren()) do
						v.Transparency = 0
					end
					for i,v in pairs (crop2:GetChildren()) do
						v.Transparency = 1
					end
				end
			end
		else
			for i,v in pairs (script.Parent:GetChildren()) do
				if v.Name == "plot" then
					local crop = v:FindFirstChild(cropName .. "1")
					for i,v in pairs (crop:GetChildren()) do
						v.Transparency = 0
					end
				end
			end
		end
	end
	
	script.Parent.ItemProperties.Finished.Value = true -- means that the process is finished and the player can collect the crops
end

script.Parent.ItemProperties.ItemId.Changed:Connect(function() -- ItemId changes when a player joins and the item was already making crops or when players triggers harvesting crop
	if script.Parent.ItemProperties.ItemId.Value ~= 0 then -- 0 means item is at rest and there's no harvesting happening
		local ItemId = script.Parent.LevelProperties.ItemId.Value
		local Data
		local playerKey = script.Parent.Parent.Parent.Plot.Owner.Value.UserId
		
		local success, err = pcall(function()
			local Data = ItemFnDS:GetAsync(playerKey .. script.Parent.Name .. tostring(script.Parent.ItemProperties.ItemId.Value))
		end)
		
		if success then
			PerformItemFunction(Data.currentTime, Data.timeWait, Data.Crop)
		else
			print("Not Found")
		end
	end
end)

There’s one more script which sets ID to 0 when the player collects the crops it’s pretty straight forward, so I am not including that in this post. [Making it 0 will mean the item is at rest and it’s not harvesting]

Let me know if you have any questions about how something works, I will try my best to answer!