1208 lines
		
	
	
		
			No EOL
		
	
	
		
			39 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1208 lines
		
	
	
		
			No EOL
		
	
	
		
			39 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const resName = GetParentResourceName();
 | 
						|
let hasDoorsCreator = null; // editing this is useless, don't do it
 | 
						|
 | 
						|
// Open/Close menu
 | 
						|
function openMenu(version, fullConfig) {
 | 
						|
	$("#dealerships-creator-version").text(version);
 | 
						|
 | 
						|
	loadDealerships();
 | 
						|
	loadVehicles();
 | 
						|
	loadClasses();
 | 
						|
	loadSettings(fullConfig);
 | 
						|
 | 
						|
    $("#dealerships-creator").show()
 | 
						|
}
 | 
						|
 | 
						|
function closeMenu() {
 | 
						|
	// Resets current active tab
 | 
						|
	$("#dealerships-creator").find(".nav-link, .tab-pane").each(function() {
 | 
						|
		if($(this).data("isDefault") == "1") {
 | 
						|
			$(this).addClass(["active", "show"])
 | 
						|
		} else {
 | 
						|
			$(this).removeClass(["active", "show"])
 | 
						|
		}
 | 
						|
	})
 | 
						|
	
 | 
						|
    $("#dealerships-creator").hide();
 | 
						|
 | 
						|
    $.post(`https://${resName}/close`)
 | 
						|
}
 | 
						|
$("#close-main-btn").click(closeMenu);
 | 
						|
 | 
						|
// Messages received by client
 | 
						|
window.addEventListener('message', (event) => {
 | 
						|
	let data = event.data;
 | 
						|
	let action = data.action;
 | 
						|
 | 
						|
	switch(action) {
 | 
						|
		case "openMenu": {
 | 
						|
			openMenu(data.version, data.fullConfig);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case "hasDoorsCreator": {
 | 
						|
			hasDoorsCreator = data.hasDoorsCreator;
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
})
 | 
						|
 | 
						|
/*
 | 
						|
███████ ███████ ████████ ████████ ██ ███    ██  ██████  ███████ 
 | 
						|
██      ██         ██       ██    ██ ████   ██ ██       ██      
 | 
						|
███████ █████      ██       ██    ██ ██ ██  ██ ██   ███ ███████ 
 | 
						|
     ██ ██         ██       ██    ██ ██  ██ ██ ██    ██      ██ 
 | 
						|
███████ ███████    ██       ██    ██ ██   ████  ██████  ███████ 
 | 
						|
*/
 | 
						|
 | 
						|
/* Discord logs */
 | 
						|
function toggleDiscordLogsInSettings(enable) {
 | 
						|
	$("#settings-mainDiscordWebhook").prop("disabled", !enable);
 | 
						|
	$("#settings-mainDiscordWebhook").prop("required", enable);
 | 
						|
	
 | 
						|
	$("#settings-specific-webooks-div").find(`.form-control`).prop("disabled", !enable);
 | 
						|
}
 | 
						|
 | 
						|
$("#settings-areDiscordLogsActive").change(function() {
 | 
						|
	let enabled = $(this).prop("checked");
 | 
						|
 | 
						|
	toggleDiscordLogsInSettings(enabled);
 | 
						|
})
 | 
						|
 | 
						|
function getSeparatedDiscordWebhooks() {
 | 
						|
	let webhooks = {};
 | 
						|
 | 
						|
	$("#settings-specific-webooks-div").find(".form-control").each(function(index, element) {
 | 
						|
		let webhook = $(element).val();
 | 
						|
		if(!webhook) return;
 | 
						|
		
 | 
						|
		let logType = $(element).data("logType");
 | 
						|
		webhooks[logType] = webhook;
 | 
						|
	});
 | 
						|
 | 
						|
	return webhooks;
 | 
						|
}
 | 
						|
/* Discord logs END */
 | 
						|
 | 
						|
function loadSettings(fullConfig) {
 | 
						|
	// Generic
 | 
						|
	$("#settings-locale").val(fullConfig.locale);
 | 
						|
	$("#settings-ace-permission").val(fullConfig.acePermission);
 | 
						|
	$("#settings-can-always-carry").prop("checked", fullConfig.canAlwaysCarryItem);
 | 
						|
 | 
						|
	// Help notification
 | 
						|
	setTomSelectValue("#settings-help-notification-script", fullConfig.helpNotification)
 | 
						|
 | 
						|
	// Discord logs
 | 
						|
	$("#settings-areDiscordLogsActive").prop("checked", fullConfig.areDiscordLogsActive);
 | 
						|
	$("#settings-mainDiscordWebhook").val(fullConfig.mainDiscordWebhook);
 | 
						|
	
 | 
						|
	toggleDiscordLogsInSettings(fullConfig.areDiscordLogsActive);	
 | 
						|
 | 
						|
	for(const[logType, webhook] of Object.entries(fullConfig.specificWebhooks)) {
 | 
						|
		$("#settings-specific-webooks-div").find(`[data-log-type="${logType}"]`).val(webhook);
 | 
						|
	}
 | 
						|
	// Discord logs - END
 | 
						|
 | 
						|
	// Player dealership
 | 
						|
	$("#settings-minutes-to-receive-vehicle-after-order").val(fullConfig.minutesToReceiveVehicleAfterOrder);
 | 
						|
	$("#settings-persistent-displayed-vehicles").prop("checked", fullConfig.persistentDisplayedVehicles);
 | 
						|
}
 | 
						|
 | 
						|
$("#settings").submit(async function(event) {
 | 
						|
	if(isThereAnyErrorInForm(event)) return;
 | 
						|
 | 
						|
	let clientSettings = {
 | 
						|
		helpNotification: $("#settings-help-notification-script").val(),
 | 
						|
	}
 | 
						|
 | 
						|
	let sharedSettings = {
 | 
						|
		locale: $("#settings-locale").val(),
 | 
						|
	}
 | 
						|
 | 
						|
	let serverSettings = {
 | 
						|
		// Generic
 | 
						|
		acePermission: $("#settings-ace-permission").val(),
 | 
						|
		canAlwaysCarryItem: $("#settings-can-always-carry").prop("checked"),
 | 
						|
 | 
						|
		// Discord logs
 | 
						|
		areDiscordLogsActive: $("#settings-areDiscordLogsActive").prop("checked"),
 | 
						|
		mainDiscordWebhook: $("#settings-mainDiscordWebhook").val(),
 | 
						|
		specificWebhooks: getSeparatedDiscordWebhooks(),
 | 
						|
 | 
						|
		// Player dealership
 | 
						|
		minutesToReceiveVehicleAfterOrder: parseInt( $("#settings-minutes-to-receive-vehicle-after-order").val() ),
 | 
						|
		persistentDisplayedVehicles: $("#settings-persistent-displayed-vehicles").prop("checked"),
 | 
						|
	}
 | 
						|
 | 
						|
	const response = await $.post(`https://${resName}/saveSettings`, JSON.stringify({
 | 
						|
		clientSettings: clientSettings,
 | 
						|
		serverSettings: serverSettings,
 | 
						|
		sharedSettings: sharedSettings
 | 
						|
	}));
 | 
						|
	showServerResponse(response);
 | 
						|
 | 
						|
	refreshTranslations(sharedSettings.locale);
 | 
						|
});
 | 
						|
 | 
						|
/*
 | 
						|
 █████  ██████  ███    ███ ██ ███    ██     ██████  ███████  █████  ██      ███████ ██████  ███████ ██   ██ ██ ██████  ███████ 
 | 
						|
██   ██ ██   ██ ████  ████ ██ ████   ██     ██   ██ ██      ██   ██ ██      ██      ██   ██ ██      ██   ██ ██ ██   ██ ██      
 | 
						|
███████ ██   ██ ██ ████ ██ ██ ██ ██  ██     ██   ██ █████   ███████ ██      █████   ██████  ███████ ███████ ██ ██████  ███████ 
 | 
						|
██   ██ ██   ██ ██  ██  ██ ██ ██  ██ ██     ██   ██ ██      ██   ██ ██      ██      ██   ██      ██ ██   ██ ██ ██           ██ 
 | 
						|
██   ██ ██████  ██      ██ ██ ██   ████     ██████  ███████ ██   ██ ███████ ███████ ██   ██ ███████ ██   ██ ██ ██      ███████ 
 | 
						|
*/
 | 
						|
let dealershipsDatatable = $("#dealerships-container").DataTable( {
 | 
						|
	"lengthMenu": [10, 15, 20],
 | 
						|
	"createdRow": function ( row, data, index ) {
 | 
						|
		$(row).addClass("clickable");
 | 
						|
 | 
						|
		$(row).click(function() {
 | 
						|
			let id = parseInt( data[0] );
 | 
						|
			editDealership(id);
 | 
						|
		})
 | 
						|
	},
 | 
						|
});
 | 
						|
 | 
						|
let dealerships = {};
 | 
						|
 | 
						|
async function loadDealerships() {
 | 
						|
	const rawDealerships = await $.post(`https://${resName}/getAllDealerships`);
 | 
						|
 | 
						|
	// Manually create the table to avoid incompatibilities due table indexing
 | 
						|
	dealerships = {};
 | 
						|
 | 
						|
	for(const[k, dealershipData] of Object.entries(rawDealerships)) {
 | 
						|
		dealerships[dealershipData.id] = dealershipData;
 | 
						|
	}
 | 
						|
 | 
						|
	dealershipsDatatable.clear();
 | 
						|
 | 
						|
	for(const[id, dealershipData] of Object.entries(dealerships)) {
 | 
						|
		dealershipsDatatable.row.add([
 | 
						|
			id,
 | 
						|
			dealershipData.label
 | 
						|
		]);
 | 
						|
	}
 | 
						|
 | 
						|
	dealershipsDatatable.draw();
 | 
						|
}
 | 
						|
 | 
						|
function setDefaultDataOfDealership() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	// Generic
 | 
						|
	$(`input[name=dealership-type][value="auto"]`).prop("checked", true).change();
 | 
						|
 | 
						|
	$("#dealership-label").val("Default");
 | 
						|
	dealershipModal.data("markerData", getDefaultMarkerCustomization());
 | 
						|
	dealershipModal.data("blipData", getDefaultBlipCustomization());
 | 
						|
	dealershipModal.data("vehiclesData", null);
 | 
						|
	$("#dealership-account-name").val("");
 | 
						|
	$("#dealership-account-name").val("bank");
 | 
						|
 | 
						|
 	// Coordinates
 | 
						|
	$("#auto-dealership-coords-list").empty();
 | 
						|
 | 
						|
	// Spawn points
 | 
						|
	$("#dealership-spawn-points-list").empty();
 | 
						|
 | 
						|
	// Showroom
 | 
						|
	$("#dealership-showroom-coords-x").val("");
 | 
						|
	$("#dealership-showroom-coords-y").val("");
 | 
						|
	$("#dealership-showroom-coords-z").val("");
 | 
						|
	$("#dealership-showroom-heading").val("");
 | 
						|
 | 
						|
	// Restrictions
 | 
						|
	dealershipModal.data("jobsData", null);
 | 
						|
	setRequiredLicenseForDealership(null);
 | 
						|
 | 
						|
	// Options
 | 
						|
	$("#dealership-pay-with-society-money").prop("checked", false).change();
 | 
						|
	$("#dealership-always-open").prop("checked", true).change();
 | 
						|
	$("#dealership-minutes-before-prices-update").val(0);
 | 
						|
	$("#dealership-is-resell-active").prop("checked", false).change();
 | 
						|
	$("#dealership-resell-percentage").val("");
 | 
						|
	dealershipModal.data("resellPointMarkerData", getDefaultResellCustomization());
 | 
						|
	setSelectedSocietiesForDealership(false);
 | 
						|
 | 
						|
	// Resell points
 | 
						|
	$("#dealership-resell-points-list").empty();
 | 
						|
 | 
						|
	// Test drive data
 | 
						|
	$("#dealership-is-test-drive-active").prop("checked", false).change();
 | 
						|
	$("#dealership-test-drive-duration").val("");
 | 
						|
	$("#dealership-test-drive-change-routing-bucket").prop("checked", false);
 | 
						|
	$("#dealership-test-drive-coords-x").val("");
 | 
						|
	$("#dealership-test-drive-coords-y").val("");
 | 
						|
	$("#dealership-test-drive-coords-z").val("");	
 | 
						|
 | 
						|
	// Player dealership
 | 
						|
	$("#player-dealership-price").val("");
 | 
						|
	$("#player-dealership-resell-percentage").val("");
 | 
						|
 | 
						|
	$("#player-dealership-coords-x").val("");
 | 
						|
	$("#player-dealership-coords-y").val("");
 | 
						|
	$("#player-dealership-coords-z").val("");
 | 
						|
 | 
						|
	$("#dealership-enter-showroom-coords-x").val("");
 | 
						|
	$("#dealership-enter-showroom-coords-y").val("");
 | 
						|
	$("#dealership-enter-showroom-coords-z").val("");
 | 
						|
 | 
						|
	// Display points
 | 
						|
	$("#player-dealership-display-points-list").empty();
 | 
						|
}
 | 
						|
 | 
						|
$("#new-dealership-btn").click(function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	// Converts from edit modal to create modal
 | 
						|
	dealershipModal.data("action", "create");
 | 
						|
	
 | 
						|
	$("#delete-dealership-btn").hide();
 | 
						|
	$("#save-dealership-btn").text( getLocalizedText("menu:create") );
 | 
						|
	
 | 
						|
	setDefaultDataOfDealership();
 | 
						|
 | 
						|
	dealershipModal.modal("show");
 | 
						|
})
 | 
						|
 | 
						|
$("#dealership-customize-blip-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	let oldBlipData = dealershipModal.data("blipData");
 | 
						|
	let blipData = await blipDialog(oldBlipData)
 | 
						|
 | 
						|
	dealershipModal.data("blipData", blipData);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-customize-marker-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
	
 | 
						|
	let oldMarkerData = dealershipModal.data("markerData");
 | 
						|
	let markerData = await markerDialog(oldMarkerData)
 | 
						|
 | 
						|
	dealershipModal.data("markerData", markerData);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-choose-vehicles-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	let oldVehicles = dealershipModal.data("vehiclesData");
 | 
						|
	let vehicles = await vehiclesDialog(oldVehicles, true);
 | 
						|
 | 
						|
	dealershipModal.data("vehiclesData", vehicles);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-choose-account-btn").click(async function() {
 | 
						|
	const accountName = await accountsDialog();
 | 
						|
 | 
						|
	$("#dealership-account-name").val(accountName);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-choose-jobs-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	let oldJobs = dealershipModal.data("jobsData");
 | 
						|
	let jobs = await jobsDialog(oldJobs);
 | 
						|
 | 
						|
	dealershipModal.data("jobsData", jobs);
 | 
						|
})
 | 
						|
 | 
						|
function setRequiredLicenseForDealership(licenseType) {
 | 
						|
	const btn = $("#dealership-choose-required-license-btn");
 | 
						|
	if(licenseType) {
 | 
						|
		btn.text(getLocalizedText("menu:license_required") + licenseType);
 | 
						|
	} else {
 | 
						|
		btn.text(getLocalizedText("menu:no_license_required"));
 | 
						|
	}
 | 
						|
 | 
						|
	btn.data("licenseType", licenseType ? licenseType : null);
 | 
						|
}
 | 
						|
 | 
						|
$("#dealership-choose-required-license-btn").click(async function() {
 | 
						|
	const requiredLicenseType = await licensesDialog();
 | 
						|
	setRequiredLicenseForDealership(requiredLicenseType);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-societies-to-send-money-to-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	let oldSocieties = dealershipModal.data("societiesData");
 | 
						|
	let societies = await societiesDialog(oldSocieties);
 | 
						|
 | 
						|
	setSelectedSocietiesForDealership(societies);
 | 
						|
})
 | 
						|
 | 
						|
async function setSelectedPayingSociety(jobName) {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	dealershipModal.data("payingSociety", jobName);
 | 
						|
 | 
						|
	const label = jobName ? await getJobLabel(jobName) : getLocalizedText("menu:none");
 | 
						|
	$("#dealership-paying-society").val(label);
 | 
						|
}
 | 
						|
 | 
						|
$("#dealership-pay-with-society-money").change(function() {
 | 
						|
	let enabled = $(this).prop("checked");
 | 
						|
 | 
						|
	$("#dealership-choose-paying-society-btn").prop("disabled", !enabled);
 | 
						|
	$("#dealership-account-name-div").toggle(!enabled);
 | 
						|
 | 
						|
	const loanInput = $("#dealership-loan-is-active");
 | 
						|
 | 
						|
	loanInput.prop("disabled", enabled)
 | 
						|
	
 | 
						|
	if(enabled) {
 | 
						|
		loanInput.prop("checked", false).change();
 | 
						|
	}
 | 
						|
 | 
						|
	if(!enabled) {
 | 
						|
		setSelectedPayingSociety(null);
 | 
						|
	}
 | 
						|
})
 | 
						|
 | 
						|
$("#dealership-choose-paying-society-btn").click(async function() {
 | 
						|
	let jobName = await singleJobDialog();
 | 
						|
	setSelectedPayingSociety(jobName);
 | 
						|
})
 | 
						|
 | 
						|
async function setSelectedSocietiesForDealership(societies) {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
	dealershipModal.data("societiesData", societies);
 | 
						|
 | 
						|
	if(!societies) {
 | 
						|
		$("#dealership-societies-to-send-money-to").val( getLocalizedText("menu:none") );
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	let jobNames = "";
 | 
						|
	let isTheFirst = true;
 | 
						|
 | 
						|
	for(const [societyName, percentage] of Object.entries(societies)) {
 | 
						|
		if(!isTheFirst) {
 | 
						|
			jobNames += ", ";
 | 
						|
		} else {
 | 
						|
			isTheFirst = false;
 | 
						|
		}
 | 
						|
 | 
						|
		jobNames += await getJobLabel(societyName) + " (" + percentage + "%)";
 | 
						|
	}
 | 
						|
 | 
						|
	$("#dealership-societies-to-send-money-to").val(jobNames);
 | 
						|
}
 | 
						|
 | 
						|
$("#dealership-loan-is-active").change(function() {
 | 
						|
	const enabled = $(this).prop("checked");
 | 
						|
 | 
						|
	$("#dealership-loan-percentage").prop("disabled", !enabled).prop("required", enabled);
 | 
						|
	$("#dealership-loan-interval").prop("disabled", !enabled).prop("required", enabled);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-is-resell-active").change(function() {
 | 
						|
	const enabled = $(this).prop("checked");
 | 
						|
 | 
						|
	$("#dealership-resell-percentage").prop("disabled", !enabled).prop("required", enabled);
 | 
						|
	$("#dealership-resell-point-customize-marker-btn").prop("disabled", !enabled);
 | 
						|
	$("#dealership-resell-div").toggle(enabled);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-resell-point-customize-marker-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
	
 | 
						|
	let oldMarkerData = dealershipModal.data("resellPointMarkerData");
 | 
						|
	let markerData = await markerDialog(oldMarkerData)
 | 
						|
 | 
						|
	dealershipModal.data("resellPointMarkerData", markerData);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-is-test-drive-active").change(function() {
 | 
						|
	const enabled = $(this).prop("checked");
 | 
						|
 | 
						|
	$("#dealership-test-drive-duration").prop("disabled", !enabled).prop("required", enabled)
 | 
						|
	$("#dealership-test-drive-change-routing-bucket").prop("disabled", !enabled)
 | 
						|
	$("#dealership-test-drive-coords-x").prop("disabled", !enabled).prop("required", enabled)
 | 
						|
	$("#dealership-test-drive-coords-y").prop("disabled", !enabled).prop("required", enabled)
 | 
						|
	$("#dealership-test-drive-coords-z").prop("disabled", !enabled).prop("required", enabled)
 | 
						|
	$("#dealership-test-drive-heading").prop("disabled", !enabled).prop("required", enabled)
 | 
						|
	$("#dealership-test-drive-current-coords-btn").prop("disabled", !enabled)
 | 
						|
})
 | 
						|
 | 
						|
$("#dealership-test-drive-current-coords-btn").click(async function() {
 | 
						|
	let data = await chooseCoords();
 | 
						|
	if(!data) return;
 | 
						|
 | 
						|
	$("#dealership-test-drive-coords-x").val(data.coords.x);
 | 
						|
	$("#dealership-test-drive-coords-y").val(data.coords.y);
 | 
						|
	$("#dealership-test-drive-coords-z").val(data.coords.z);
 | 
						|
	$("#dealership-test-drive-heading").val(data.heading);
 | 
						|
});
 | 
						|
 | 
						|
function addPointToPointsList(listDiv, wantsHeading, wantsRadius, pointData) {
 | 
						|
	let div = $(`
 | 
						|
		<div class="d-flex gap-1 align-items-center justify-content-center my-2 coords-div">
 | 
						|
			<button type="button" class="btn-close delete-coords-btn me-2"></button>
 | 
						|
 | 
						|
			<div class="form-floating text-body col">
 | 
						|
				<input type="number" step="0.01" class="form-control form-control-sm coords-x" placeholder="X" required>
 | 
						|
				<label>${getLocalizedText("menu:x")}</label>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div class="form-floating text-body col">
 | 
						|
				<input type="number" step="0.01" class="form-control form-control-sm coords-y" placeholder="Y" required>
 | 
						|
				<label>${getLocalizedText("menu:y")}</label>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div class="form-floating text-body col">
 | 
						|
				<input type="number" step="0.01" class="form-control form-control-sm coords-z" placeholder="Z" required>
 | 
						|
				<label>${getLocalizedText("menu:z")}</label>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div class="form-floating text-body col heading-div">
 | 
						|
				<input type="number" step="0.01" class="form-control form-control-sm heading" placeholder="Heading" required>
 | 
						|
				<label>${getLocalizedText("menu:heading")}</label>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<div class="form-floating text-body col radius-div">
 | 
						|
				<input type="number" class="form-control form-control-sm radius" value="5" placeholder="Radius" required>
 | 
						|
				<label>${getLocalizedText("menu:radius")}</label>
 | 
						|
			</div>
 | 
						|
 | 
						|
			<button type="button" class="btn btn-secondary col-auto current-coords-btn" data-bs-toggle="tooltip" data-bs-placement="top" title="${getLocalizedText("menu:choose_coords")}"><i class="bi bi-arrow-down-square"></i></button>	
 | 
						|
		</div>
 | 
						|
	`)
 | 
						|
 | 
						|
	if(!wantsHeading) {
 | 
						|
		div.find(".heading-div").remove();
 | 
						|
	}
 | 
						|
 | 
						|
	if(!wantsRadius) {
 | 
						|
		div.find(".radius-div").remove();
 | 
						|
	}
 | 
						|
 | 
						|
	div.find(".current-coords-btn").click(async function() {
 | 
						|
		let data = await chooseCoords();
 | 
						|
		if(!data) return;
 | 
						|
 | 
						|
		div.find(".coords-x").val(data.coords.x);
 | 
						|
		div.find(".coords-y").val(data.coords.y);
 | 
						|
		div.find(".coords-z").val(data.coords.z);
 | 
						|
		div.find(".heading").val(data.heading);
 | 
						|
	}).tooltip();
 | 
						|
 | 
						|
	div.find(".delete-coords-btn").click(function() {
 | 
						|
		div.remove();
 | 
						|
	});
 | 
						|
 | 
						|
	if(pointData) {
 | 
						|
		let coords = null;
 | 
						|
		
 | 
						|
		if(wantsHeading || wantsRadius) {
 | 
						|
			coords = pointData.coords;
 | 
						|
			div.find(".heading").val(pointData.heading);
 | 
						|
			div.find(".radius").val(pointData.radius);
 | 
						|
		} else {
 | 
						|
			coords = pointData;
 | 
						|
		}
 | 
						|
 | 
						|
		div.find(".coords-x").val(coords.x);
 | 
						|
		div.find(".coords-y").val(coords.y);
 | 
						|
		div.find(".coords-z").val(coords.z);
 | 
						|
	}
 | 
						|
 | 
						|
	listDiv.append(div);
 | 
						|
}
 | 
						|
 | 
						|
function setPointToPointsList(listDiv, wantsHeading, wantsRadius, pointsList) {
 | 
						|
	listDiv.empty();
 | 
						|
 | 
						|
	if(!pointsList) return;
 | 
						|
	
 | 
						|
	for(const pointData of pointsList) {
 | 
						|
		addPointToPointsList(listDiv, wantsHeading, wantsRadius, pointData);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function getPointFromPointsList(listDiv) {
 | 
						|
	let pointsList = [];
 | 
						|
 | 
						|
	listDiv.find(".coords-div").each(function() {
 | 
						|
		const coords = {
 | 
						|
			x: parseFloat( $(this).find(".coords-x").val() ),
 | 
						|
			y: parseFloat( $(this).find(".coords-y").val() ),
 | 
						|
			z: parseFloat( $(this).find(".coords-z").val() ),
 | 
						|
		}
 | 
						|
 | 
						|
		const headingInput = $(this).find(".heading");
 | 
						|
		const radiusInput = $(this).find(".radius");
 | 
						|
 | 
						|
		if(headingInput.prop("required")) {
 | 
						|
			const heading = parseFloat( headingInput.val() );
 | 
						|
			const radius = parseFloat( radiusInput.val() );
 | 
						|
 | 
						|
			pointsList.push({
 | 
						|
				coords,
 | 
						|
				heading,
 | 
						|
				radius
 | 
						|
			});
 | 
						|
		} else {
 | 
						|
			pointsList.push(coords);
 | 
						|
		}
 | 
						|
		
 | 
						|
	});
 | 
						|
 | 
						|
	return pointsList;
 | 
						|
}
 | 
						|
 | 
						|
$("#dealership-add-coordinates-btn").click(function() {
 | 
						|
	const div = $("#auto-dealership-coords-list");
 | 
						|
	addPointToPointsList(div);
 | 
						|
});
 | 
						|
 | 
						|
$("#player-dealership-current-coords-btn").click(async function() {
 | 
						|
	let data = await chooseCoords();
 | 
						|
	if(!data) return;
 | 
						|
 | 
						|
	$("#player-dealership-coords-x").val(data.coords.x);
 | 
						|
	$("#player-dealership-coords-y").val(data.coords.y);
 | 
						|
	$("#player-dealership-coords-z").val(data.coords.z);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-add-spawnpoint-btn").click(async function() {
 | 
						|
	const div = $("#dealership-spawn-points-list");
 | 
						|
	addPointToPointsList(div, true, true);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-add-resell-point-btn").click(async function() {
 | 
						|
	const div = $("#dealership-resell-points-list");
 | 
						|
	addPointToPointsList(div, false, false);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-add-display-point-btn").click(async function() {
 | 
						|
	const div = $("#player-dealership-display-points-list");
 | 
						|
	addPointToPointsList(div, true, true);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-enter-showroom-current-coords-btn").click(async function() {
 | 
						|
	let data = await chooseCoords();
 | 
						|
	if(!data) return;
 | 
						|
 | 
						|
	$("#dealership-enter-showroom-coords-x").val(data.coords.x);
 | 
						|
	$("#dealership-enter-showroom-coords-y").val(data.coords.y);
 | 
						|
	$("#dealership-enter-showroom-coords-z").val(data.coords.z);
 | 
						|
});
 | 
						|
 | 
						|
$("#dealership-showroom-current-coords-btn").click(async function() {
 | 
						|
	let data = await chooseCoords();
 | 
						|
	if(!data) return;
 | 
						|
 | 
						|
	$("#dealership-showroom-coords-x").val(data.coords.x);
 | 
						|
	$("#dealership-showroom-coords-y").val(data.coords.y);
 | 
						|
	$("#dealership-showroom-coords-z").val(data.coords.z);
 | 
						|
	$("#dealership-showroom-heading").val(data.heading);
 | 
						|
});
 | 
						|
 | 
						|
function toggleAutoDealershipFields(hasToShow) {
 | 
						|
	$("#dealership-account-name-div").toggle(hasToShow);
 | 
						|
	$("#dealership-account-name").prop("required", hasToShow);
 | 
						|
 | 
						|
	$("#auto-dealership-coords-div").toggle(hasToShow);
 | 
						|
	$("#auto-dealership-coords-list").find("input").prop("required", hasToShow);
 | 
						|
 | 
						|
	$("#dealership-restrictions-div").toggle(hasToShow);
 | 
						|
	$("#dealership-paying-society-div").toggle(hasToShow);
 | 
						|
 | 
						|
	$("#dealership-resell-points-div").toggle(hasToShow);
 | 
						|
	$("#dealership-is-resell-active").prop("checked");
 | 
						|
 | 
						|
	// options to disable to avoid issues when switching to player dealership
 | 
						|
	if(!hasToShow) {
 | 
						|
		$("#dealership-pay-with-society-money").prop("checked", false).change();
 | 
						|
		$("#dealership-is-resell-active").prop("checked", false).change();
 | 
						|
		$("#dealership-resell-points-list").empty();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function togglePlayerOwnedDealershipField(hasToShow) {
 | 
						|
	$("#player-dealership-coords-div").toggle(hasToShow);
 | 
						|
	$("#player-dealership-coords-div").find("input").prop("required", hasToShow);
 | 
						|
 | 
						|
	$("#player-dealership-purchase-div").toggle(hasToShow);
 | 
						|
	$("#player-dealership-purchase-div").find("input").prop("required", hasToShow);
 | 
						|
 | 
						|
	$("#player-dealership-display-div").toggle(hasToShow);
 | 
						|
	$("#player-dealership-display-div").find("input").prop("required", hasToShow);
 | 
						|
 | 
						|
	$("#player-dealership-enter-showroom-div").toggle(hasToShow);
 | 
						|
	$("#player-dealership-enter-showroom-div").find("input").prop("required", hasToShow);
 | 
						|
}
 | 
						|
 | 
						|
$("input[name=dealership-type]").change(function() {
 | 
						|
	const type = $(this).val();
 | 
						|
 | 
						|
	toggleAutoDealershipFields(type == "auto");
 | 
						|
	togglePlayerOwnedDealershipField(type == "player");
 | 
						|
});
 | 
						|
 | 
						|
function setSharedDealershipData(data) {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	// Generic
 | 
						|
	dealershipModal.data("blipData", data.blipData);
 | 
						|
	dealershipModal.data("markerData", data.markerData);
 | 
						|
	dealershipModal.data("vehiclesData", data.vehiclesData);
 | 
						|
	$("#dealership-account-name").val(data.accountName);
 | 
						|
 | 
						|
	// Spawn points
 | 
						|
	setPointToPointsList($("#dealership-spawn-points-list"), true, true, data.spawnPointsList);
 | 
						|
 | 
						|
	// Showroom
 | 
						|
	$("#dealership-showroom-coords-x").val(data.showroomPoint.coords.x);
 | 
						|
	$("#dealership-showroom-coords-y").val(data.showroomPoint.coords.y);
 | 
						|
	$("#dealership-showroom-coords-z").val(data.showroomPoint.coords.z);
 | 
						|
	$("#dealership-showroom-heading").val(data.showroomPoint.heading);
 | 
						|
 | 
						|
	// Options
 | 
						|
	dealershipModal.data("societiesData", data.societiesToSendMoneyTo);
 | 
						|
	$("#dealership-pay-with-society-money").prop("checked", data.payWithSocietyMoney).change();
 | 
						|
 | 
						|
	// Loan data
 | 
						|
	$("#dealership-loan-is-active").prop("checked", data.loanData.isActive).change();
 | 
						|
	$("#dealership-loan-percentage").val(data.loanData.percentage).change();
 | 
						|
	$("#dealership-loan-interval").val(data.loanData.intervalDays);
 | 
						|
 | 
						|
	// Test drive data
 | 
						|
	$("#dealership-is-test-drive-active").prop("checked", data.testDriveData.isActive).change();
 | 
						|
	$("#dealership-test-drive-duration").val(data.testDriveData.duration);
 | 
						|
	$("#dealership-test-drive-change-routing-bucket").prop("checked", data.testDriveData.changeRoutingBucket);
 | 
						|
	$("#dealership-test-drive-coords-x").val(data.testDriveData.pointData.coords.x);
 | 
						|
	$("#dealership-test-drive-coords-y").val(data.testDriveData.pointData.coords.y);
 | 
						|
	$("#dealership-test-drive-coords-z").val(data.testDriveData.pointData.coords.z);
 | 
						|
	$("#dealership-test-drive-heading").val(data.testDriveData.pointData.heading);
 | 
						|
}
 | 
						|
 | 
						|
function setAutoDealershipData(data) {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	// Coordinates
 | 
						|
	setPointToPointsList($("#auto-dealership-coords-list"), false, false, data.coordinatesList);
 | 
						|
 | 
						|
	// Restrictions
 | 
						|
	dealershipModal.data("jobsData", data.jobsData);
 | 
						|
	setRequiredLicenseForDealership(data.requiredLicense)
 | 
						|
 | 
						|
	// Options
 | 
						|
	dealershipModal.data("payingSociety", data.payingSociety);
 | 
						|
 | 
						|
	// Resell data
 | 
						|
	$("#dealership-is-resell-active").prop("checked", data.resellData.isActive).change();
 | 
						|
	$("#dealership-resell-percentage").val(data.resellData.percentage);
 | 
						|
	setPointToPointsList($("#dealership-resell-points-list"), false, false, data.resellData.points);
 | 
						|
	dealershipModal.data("resellPointMarkerData", data.resellData.markerData);
 | 
						|
}
 | 
						|
 | 
						|
function setPlayerDealershipData(data) {
 | 
						|
	// Generic
 | 
						|
	$("#player-dealership-price").val(data.price);
 | 
						|
	$("#player-dealership-resell-percentage").val(data.resellPercentage);
 | 
						|
 | 
						|
	// Coordinates
 | 
						|
	$("#player-dealership-coords-x").val(data.coordinates.x);
 | 
						|
	$("#player-dealership-coords-y").val(data.coordinates.y);
 | 
						|
	$("#player-dealership-coords-z").val(data.coordinates.z);
 | 
						|
 | 
						|
	// Display points
 | 
						|
	setPointToPointsList($("#player-dealership-display-points-list"), true, true, data.displayPointsList);
 | 
						|
 | 
						|
	// Enter showroom coords
 | 
						|
	$("#dealership-enter-showroom-coords-x").val(data.enterShowroomCoords.x);
 | 
						|
	$("#dealership-enter-showroom-coords-y").val(data.enterShowroomCoords.y);
 | 
						|
	$("#dealership-enter-showroom-coords-z").val(data.enterShowroomCoords.z);
 | 
						|
}
 | 
						|
 | 
						|
function editDealership(id) {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
	const dealershipInfo = dealerships[id];
 | 
						|
 | 
						|
	dealershipModal.data("dealershipId", id);
 | 
						|
	dealershipModal.data("action", "edit");
 | 
						|
 | 
						|
	$("#delete-dealership-btn").show();
 | 
						|
	$("#save-dealership-btn").text(getLocalizedText("menu:confirm"));
 | 
						|
 | 
						|
	const data = dealershipInfo.data;
 | 
						|
 | 
						|
	// Generic
 | 
						|
	$("#dealership-label").val(dealershipInfo.label);
 | 
						|
	
 | 
						|
	setSharedDealershipData(data);
 | 
						|
 | 
						|
	if(dealershipInfo.type == "auto") {
 | 
						|
		setAutoDealershipData(data);
 | 
						|
	} else {
 | 
						|
		setPlayerDealershipData(data);
 | 
						|
	}
 | 
						|
		
 | 
						|
	// As last input, so all elements are already added to the DOM
 | 
						|
	$(`input[name=dealership-type][value=${dealershipInfo.type}]`).prop("checked", true).change();
 | 
						|
 | 
						|
	dealershipModal.modal("show");
 | 
						|
}
 | 
						|
 | 
						|
function getSharedDealershipData() {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	return {
 | 
						|
		// Generic
 | 
						|
		blipData: dealershipModal.data("blipData"),
 | 
						|
		markerData: dealershipModal.data("markerData"),
 | 
						|
		vehiclesData: dealershipModal.data("vehiclesData"),
 | 
						|
		accountName: $("#dealership-account-name").val(),
 | 
						|
 | 
						|
		// Spawn points
 | 
						|
		spawnPointsList: getPointFromPointsList( $("#dealership-spawn-points-list") ),
 | 
						|
 | 
						|
		// Showroom
 | 
						|
		showroomPoint: {
 | 
						|
			coords: {
 | 
						|
				x: parseFloat( $("#dealership-showroom-coords-x").val() ),
 | 
						|
				y: parseFloat( $("#dealership-showroom-coords-y").val() ),
 | 
						|
				z: parseFloat( $("#dealership-showroom-coords-z").val() ),
 | 
						|
			},
 | 
						|
			heading: parseFloat( $("#dealership-showroom-heading").val() ),
 | 
						|
		},
 | 
						|
 | 
						|
		// Options
 | 
						|
		societiesToSendMoneyTo: dealershipModal.data("societiesData"),
 | 
						|
		payWithSocietyMoney: $("#dealership-pay-with-society-money").prop("checked"),
 | 
						|
 | 
						|
		loanData: {
 | 
						|
			isActive: $("#dealership-loan-is-active").prop("checked"),
 | 
						|
			percentage: parseInt( $("#dealership-loan-percentage").val() ),
 | 
						|
			intervalDays: parseInt( $("#dealership-loan-interval").val() )
 | 
						|
		},
 | 
						|
 | 
						|
		testDriveData: {
 | 
						|
			isActive: $("#dealership-is-test-drive-active").prop("checked"),
 | 
						|
			duration: parseInt( $("#dealership-test-drive-duration").val() ),
 | 
						|
			changeRoutingBucket: $("#dealership-test-drive-change-routing-bucket").prop("checked"),
 | 
						|
			pointData: {
 | 
						|
				coords: {
 | 
						|
					x: parseFloat( $("#dealership-test-drive-coords-x").val() ),
 | 
						|
					y: parseFloat( $("#dealership-test-drive-coords-y").val() ),
 | 
						|
					z: parseFloat( $("#dealership-test-drive-coords-z").val() ),
 | 
						|
				},
 | 
						|
				heading: parseFloat( $("#dealership-test-drive-heading").val() ),
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function getAutoDealershipData() {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
 | 
						|
	const sharedData = getSharedDealershipData();
 | 
						|
	const data = {
 | 
						|
		// Coordinates
 | 
						|
		coordinatesList: getPointFromPointsList( $("#auto-dealership-coords-list") ),
 | 
						|
 | 
						|
		// Restrictions
 | 
						|
		jobsData: dealershipModal.data("jobsData"),
 | 
						|
		requiredLicense: $("#dealership-choose-required-license-btn").data("licenseType"),
 | 
						|
 | 
						|
		// Options
 | 
						|
		payingSociety: dealershipModal.data("payingSociety"),
 | 
						|
		resellData: {
 | 
						|
			isActive: $("#dealership-is-resell-active").prop("checked"),
 | 
						|
			percentage: parseInt( $("#dealership-resell-percentage").val() ),
 | 
						|
			points: getPointFromPointsList( $("#dealership-resell-points-list") ),
 | 
						|
			markerData: dealershipModal.data("resellPointMarkerData")
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	return {...sharedData, ...data}
 | 
						|
}
 | 
						|
 | 
						|
function getPlayerDealershipData() {
 | 
						|
	const sharedData = getSharedDealershipData();
 | 
						|
	const data = {
 | 
						|
		// Generic
 | 
						|
		price: parseInt( $("#player-dealership-price").val() ),
 | 
						|
		resellPercentage: parseInt( $("#player-dealership-resell-percentage").val() ),
 | 
						|
 | 
						|
		// Coordinates
 | 
						|
		coordinates: {
 | 
						|
			x: parseFloat( $("#player-dealership-coords-x").val() ),
 | 
						|
			y: parseFloat( $("#player-dealership-coords-y").val() ),
 | 
						|
			z: parseFloat( $("#player-dealership-coords-z").val() ),
 | 
						|
		},
 | 
						|
 | 
						|
		// Display points
 | 
						|
		displayPointsList: getPointFromPointsList( $("#player-dealership-display-points-list") ),
 | 
						|
 | 
						|
		// Enter showroom coords
 | 
						|
		enterShowroomCoords: {
 | 
						|
			x: parseFloat( $("#dealership-enter-showroom-coords-x").val() ),
 | 
						|
			y: parseFloat( $("#dealership-enter-showroom-coords-y").val() ),
 | 
						|
			z: parseFloat( $("#dealership-enter-showroom-coords-z").val() ),
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return {...sharedData, ...data}
 | 
						|
}
 | 
						|
 | 
						|
$("#dealership-form").submit(async function(event) {
 | 
						|
	if(isThereAnyErrorInForm(event)) return;
 | 
						|
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
	let action = dealershipModal.data("action");
 | 
						|
 | 
						|
	const dealershipType = $("input[name=dealership-type]:checked").val();
 | 
						|
 | 
						|
	let dealershipInfo = {
 | 
						|
		label: $("#dealership-label").val(),
 | 
						|
		type: dealershipType,
 | 
						|
 | 
						|
		data: dealershipType == "auto" ? getAutoDealershipData() : getPlayerDealershipData()
 | 
						|
	}
 | 
						|
	
 | 
						|
	let success = null;
 | 
						|
 | 
						|
	switch(action) {
 | 
						|
		case "create": {
 | 
						|
			success = await $.post(`https://${resName}/createDealership`, JSON.stringify(dealershipInfo));
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case "edit": {
 | 
						|
			success = await $.post(`https://${resName}/updateDealership`, JSON.stringify({dealershipId: dealershipModal.data("dealershipId"), dealershipInfo: dealershipInfo}));
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(!success) return;
 | 
						|
 | 
						|
	dealershipModal.modal("hide");
 | 
						|
	loadDealerships();
 | 
						|
})
 | 
						|
 | 
						|
$("#delete-dealership-btn").click(async function() {
 | 
						|
	let dealershipModal = $("#dealership-modal");
 | 
						|
	let dealershipId = dealershipModal.data("dealershipId");
 | 
						|
 | 
						|
	const success = await $.post(`https://${resName}/deleteDealership`, JSON.stringify({dealershipId: dealershipId}));
 | 
						|
	if(!success) return;
 | 
						|
 | 
						|
	dealershipModal.modal("hide");
 | 
						|
	loadDealerships();
 | 
						|
});
 | 
						|
 | 
						|
$("#import-dealership-btn").click(async function() {
 | 
						|
	const dealershipModal = $("#dealership-modal");
 | 
						|
	const dealershipId = dealershipModal.data("dealershipId");
 | 
						|
	
 | 
						|
	const importedData = await dealershipsDialog();
 | 
						|
 | 
						|
	const oldAction = dealershipModal.data("action"); // To remember if it's an edit or create
 | 
						|
 | 
						|
	dealerships[dealershipId] = importedData;
 | 
						|
	editDealership(dealershipId);
 | 
						|
	dealershipModal.data("action", oldAction);
 | 
						|
})
 | 
						|
 | 
						|
$(document).keyup(function(e) {
 | 
						|
	if (e.key === "Escape") {
 | 
						|
		exitShowroom();
 | 
						|
        closeMenu();
 | 
						|
	}
 | 
						|
});
 | 
						|
 | 
						|
/*
 | 
						|
██    ██ ███████ ██   ██ ██  ██████ ██      ███████ ███████ 
 | 
						|
██    ██ ██      ██   ██ ██ ██      ██      ██      ██      
 | 
						|
██    ██ █████   ███████ ██ ██      ██      █████   ███████ 
 | 
						|
 ██  ██  ██      ██   ██ ██ ██      ██      ██           ██ 
 | 
						|
  ████   ███████ ██   ██ ██  ██████ ███████ ███████ ███████ 
 | 
						|
*/
 | 
						|
 | 
						|
async function takeVehicleImage(spawnName) {
 | 
						|
	$('html').hide();
 | 
						|
	await $.post(`https://${resName}/takeVehicleImage`, JSON.stringify({spawnName}));
 | 
						|
	$('html').show();
 | 
						|
}
 | 
						|
 | 
						|
async function deleteVehicle(spawnName) {
 | 
						|
	if(!await confirmDeletion()) return;
 | 
						|
 | 
						|
	const response = await $.post(`https://${resName}/deleteVehicle`, JSON.stringify({spawnName}));
 | 
						|
	showServerResponse(response);
 | 
						|
 | 
						|
	if(response === true) {
 | 
						|
		loadVehicles();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
let vehiclesDatatable = $("#vehicles-container").DataTable( {
 | 
						|
	"lengthMenu": [15, 30, 50],
 | 
						|
	"order": [
 | 
						|
		[ $('th[data-translation-id="menu:valid"]').index(), 'desc' ],
 | 
						|
		[ $('th[data-translation-id="menu:spawn_name"]').index(), 'asc' ]
 | 
						|
	],
 | 
						|
	"columnDefs": [
 | 
						|
        { 
 | 
						|
            "targets": -1, // Last column
 | 
						|
            "data": null,
 | 
						|
			"className": "col-1",
 | 
						|
            "defaultContent": `
 | 
						|
			<div class="d-inline-flex gap-3">
 | 
						|
				<button class='btn btn-danger py-0 px-2 delete-vehicle-btn' data-bs-toggle="tooltip" data-bs-placement="top" title="Delete"><i class=\"bi bi-trash\"></i></button>
 | 
						|
				<button class='btn btn-info py-0 px-2 take-image-btn' data-bs-toggle="tooltip" data-bs-placement="top" title="Take image"><i class=\"bi bi-image\"></i></button>
 | 
						|
			</div>
 | 
						|
			`
 | 
						|
        },
 | 
						|
        { 
 | 
						|
            "targets": -3, // 'type' column
 | 
						|
			"className": "col-1",
 | 
						|
        }
 | 
						|
    ],
 | 
						|
	"createdRow": function (row, data, index) {
 | 
						|
		$('td', row).css('white-space', 'nowrap').addClass("py-3");
 | 
						|
 | 
						|
		let vehicleData = data[data.length - 1]; 
 | 
						|
 | 
						|
		$(row).find(".delete-vehicle-btn").click(function() {
 | 
						|
			deleteVehicle(vehicleData.spawnName);
 | 
						|
		}).tooltip();
 | 
						|
 | 
						|
		$(row).find(".take-image-btn").click(function() {
 | 
						|
			takeVehicleImage(vehicleData.spawnName);
 | 
						|
		}).tooltip();
 | 
						|
	}
 | 
						|
});
 | 
						|
 | 
						|
let vehicles = {};
 | 
						|
 | 
						|
async function loadVehicles() {
 | 
						|
	const rawVehicles = await $.post(`https://${resName}/getAllVehicles`);
 | 
						|
 | 
						|
	// Manually create the table to avoid incompatibilities due table indexing
 | 
						|
	vehicles = {};
 | 
						|
 | 
						|
	for(const[k, vehicleData] of Object.entries(rawVehicles)) {
 | 
						|
		vehicles[vehicleData.spawnName] = vehicleData;
 | 
						|
	}
 | 
						|
 | 
						|
	vehiclesDatatable.clear();
 | 
						|
 | 
						|
	for(const[id, vehicleData] of Object.entries(vehicles)) {
 | 
						|
		const spawnName = vehicleData.isValid 
 | 
						|
			? vehicleData.spawnName 
 | 
						|
			: `<span class="text-danger fw-bold">${vehicleData.spawnName}</span>`;
 | 
						|
	
 | 
						|
		vehiclesDatatable.row.add([
 | 
						|
			spawnName ?? "???",
 | 
						|
			vehicleData.label ?? "???",
 | 
						|
			vehicleData.class ?? "???",
 | 
						|
			vehicleData.type ?? "???",
 | 
						|
			vehicleData.isValid ? "✅" : "❌",
 | 
						|
			vehicleData
 | 
						|
		]);
 | 
						|
	}	
 | 
						|
 | 
						|
	vehiclesDatatable.draw();
 | 
						|
}
 | 
						|
 | 
						|
async function setDefaultDataOfVehicle() {
 | 
						|
	$("#create-vehicle-spawn-name").val("");
 | 
						|
	$("#create-vehicle-label").val("");
 | 
						|
	$("#create-vehicle-class").val("sport");
 | 
						|
	$("input[name=create-vehicle-type][value=car]").prop("checked", true).change();
 | 
						|
 | 
						|
	// Remove all things in select #create-vehicle-class
 | 
						|
	$("#create-vehicle-class").empty();
 | 
						|
	const classes = await $.post(`https://${resName}/getAllClasses`);
 | 
						|
	for(const [k, classData] of Object.entries(classes)) {
 | 
						|
		$("#create-vehicle-class").append(`<option value="${classData.id}">${classData.label}</option>`);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
$("#new-vehicle-btn").click(function() {
 | 
						|
	let vehicleModal = $("#vehicle-modal");
 | 
						|
	
 | 
						|
	setDefaultDataOfVehicle();
 | 
						|
 | 
						|
	vehicleModal.modal("show");
 | 
						|
});
 | 
						|
 | 
						|
async function isVehicleValid(spawnName) {
 | 
						|
	return await $.post(`https://${resName}/isVehicleValid`, JSON.stringify({spawnName}));
 | 
						|
}
 | 
						|
 | 
						|
$("#vehicle-form").submit(async function(event) {
 | 
						|
	if(isThereAnyErrorInForm(event)) return;
 | 
						|
 | 
						|
	let vehicleModal = $("#vehicle-modal");
 | 
						|
 | 
						|
	const vehicleInfo = {
 | 
						|
		spawnName: $("#create-vehicle-spawn-name").val(),
 | 
						|
		label: $("#create-vehicle-label").val(),
 | 
						|
		class: $("#create-vehicle-class").val(),
 | 
						|
		type: $("input[name=create-vehicle-type]:checked").val(),
 | 
						|
	}
 | 
						|
 | 
						|
	if(!await isVehicleValid(vehicleInfo.spawnName)) {
 | 
						|
		swal("ERROR", `Spawn name not valid!`, "error");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	let submitButton = event.originalEvent.submitter;
 | 
						|
	let submitButtonName = submitButton.name;
 | 
						|
 | 
						|
	const response = await $.post(`https://${resName}/createVehicle`, JSON.stringify(vehicleInfo));
 | 
						|
	showServerResponse(response);
 | 
						|
	if(response !== true) return;
 | 
						|
 | 
						|
	if (submitButtonName == "create-vehicle-with-image-btn") {
 | 
						|
		takeVehicleImage(vehicleInfo.spawnName);
 | 
						|
	}
 | 
						|
 | 
						|
	vehicleModal.modal("hide");
 | 
						|
	loadVehicles();
 | 
						|
})
 | 
						|
 | 
						|
$("#all-vehicles-picture-btn").click(async function() {
 | 
						|
	if(!await confirmDeletion()) return;
 | 
						|
	closeMenu();
 | 
						|
	$.post(`https://${resName}/takeAllVehiclesImages`);
 | 
						|
})
 | 
						|
 | 
						|
/*
 | 
						|
 ██████ ██       █████  ███████ ███████ ███████ ███████ 
 | 
						|
██      ██      ██   ██ ██      ██      ██      ██      
 | 
						|
██      ██      ███████ ███████ ███████ █████   ███████ 
 | 
						|
██      ██      ██   ██      ██      ██ ██           ██ 
 | 
						|
 ██████ ███████ ██   ██ ███████ ███████ ███████ ███████ 
 | 
						|
*/
 | 
						|
let classesDatatable = $("#classes-container").DataTable( {
 | 
						|
	"lengthMenu": [15, 30, 50],
 | 
						|
	"createdRow": function (row, data, index) {
 | 
						|
		$('td', row).css('white-space', 'nowrap').addClass("py-3");
 | 
						|
		$(row).addClass("clickable");
 | 
						|
 | 
						|
		let classData = data[data.length - 1]; 
 | 
						|
 | 
						|
		$(row).click(function() {
 | 
						|
			editClass(classData.id);
 | 
						|
		});
 | 
						|
	}
 | 
						|
});
 | 
						|
 | 
						|
let classes = {};
 | 
						|
 | 
						|
async function loadClasses() {
 | 
						|
	const rawClasses = await $.post(`https://${resName}/getAllClasses`);
 | 
						|
 | 
						|
	// Manually create the table to avoid incompatibilities due table indexing
 | 
						|
	classes = {};
 | 
						|
 | 
						|
	for(const[k, classData] of Object.entries(rawClasses)) {
 | 
						|
		classes[classData.id] = classData;
 | 
						|
	}
 | 
						|
 | 
						|
	classesDatatable.clear();
 | 
						|
 | 
						|
	for(const[id, classData] of Object.entries(classes)) {	
 | 
						|
		classesDatatable.row.add([
 | 
						|
			classData.id,
 | 
						|
			classData.label,
 | 
						|
			classData
 | 
						|
		]);
 | 
						|
	}	
 | 
						|
 | 
						|
	classesDatatable.draw();
 | 
						|
}
 | 
						|
 | 
						|
function setClassConfig(config={}){
 | 
						|
	$("#create-class-id").val(config.id);
 | 
						|
	$("#create-class-label").val(config.label);
 | 
						|
 | 
						|
	$("#create-class-id").prop("disabled", config.id ? true : false);
 | 
						|
}
 | 
						|
 | 
						|
$("#new-class-btn").click(function() {
 | 
						|
	let classModal = $("#class-modal");
 | 
						|
 | 
						|
	// Converts from edit modal to create modal
 | 
						|
	classModal.data("action", "create");
 | 
						|
		
 | 
						|
	$("#delete-class-btn").hide();
 | 
						|
	$("#save-class-btn").text( getLocalizedText("menu:create") );
 | 
						|
	
 | 
						|
	setClassConfig();
 | 
						|
 | 
						|
	classModal.modal("show");
 | 
						|
});
 | 
						|
 | 
						|
$("#class-form").submit(async function(event) {
 | 
						|
	if(isThereAnyErrorInForm(event)) return;
 | 
						|
 | 
						|
	let classModal = $("#class-modal");
 | 
						|
 | 
						|
	const classInfo = {
 | 
						|
		id: $("#create-class-id").val(),
 | 
						|
		label: $("#create-class-label").val(),
 | 
						|
	}
 | 
						|
 | 
						|
	let action = classModal.data("action");
 | 
						|
 | 
						|
	let response = null;
 | 
						|
 | 
						|
	switch(action) {
 | 
						|
		case "create": {
 | 
						|
			response = await $.post(`https://${resName}/createClass`, JSON.stringify(classInfo));
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		case "edit": {
 | 
						|
			response = await $.post(`https://${resName}/updateClass`, JSON.stringify({classId: classInfo.id, classInfo}));
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	showServerResponse(response);
 | 
						|
	if(response !== true) return;
 | 
						|
 | 
						|
	classModal.modal("hide");
 | 
						|
	loadClasses();
 | 
						|
})
 | 
						|
 | 
						|
function editClass(classId) {
 | 
						|
	const classModal = $("#class-modal");
 | 
						|
	const classInfo = classes[classId];
 | 
						|
 | 
						|
	classModal.data("classId", classId);
 | 
						|
	classModal.data("action", "edit");
 | 
						|
 | 
						|
	$("#delete-class-btn").show();
 | 
						|
	$("#save-class-btn").text(getLocalizedText("menu:confirm"));
 | 
						|
 | 
						|
	setClassConfig(classInfo);
 | 
						|
		
 | 
						|
	classModal.modal("show");
 | 
						|
}
 | 
						|
 | 
						|
$("#delete-class-btn").click(async function() {
 | 
						|
	if(!await confirmDeletion()) return;
 | 
						|
	
 | 
						|
	let classModal = $("#class-modal");
 | 
						|
	let classId = classModal.data("classId");
 | 
						|
 | 
						|
	const response = await $.post(`https://${resName}/deleteClass`, JSON.stringify({classId}));
 | 
						|
	showServerResponse(response);
 | 
						|
	if(response !== true) return;
 | 
						|
 | 
						|
	classModal.modal("hide");
 | 
						|
	loadClasses();
 | 
						|
}); |