Initial
This commit is contained in:
parent
542ca5a14e
commit
aff781e04a
8 changed files with 548 additions and 37 deletions
26
endpoint_handlers/licenseinfo.js
Normal file
26
endpoint_handlers/licenseinfo.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const LICENCEINFO_ENDPOINT = 'https://fp.trafikverket.se/Boka/licence-information'
|
||||||
|
|
||||||
|
async function getLicenceInfo(req, res) {
|
||||||
|
// Check for the required parameters
|
||||||
|
let response = await fetch(LICENCEINFO_ENDPOINT, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
|
||||||
|
},
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// licenceId: licenceId,
|
||||||
|
// }),
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
res.status(500).json({ message: 'Something went wrong' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = await response.json()
|
||||||
|
// console.log(json)
|
||||||
|
|
||||||
|
res.json(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getLicenceInfo;
|
52
endpoint_handlers/metadata.js
Normal file
52
endpoint_handlers/metadata.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
const METADATA_ENDPOINT = 'https://fp.trafikverket.se/boka/search-information'
|
||||||
|
|
||||||
|
const METADATA_TEMPLATE = {
|
||||||
|
"bookingSession": {
|
||||||
|
"socialSecurityNumber": "",
|
||||||
|
"licenceId": "",
|
||||||
|
"bookingModeId": 0,
|
||||||
|
"ignoreDebt": false,
|
||||||
|
"ignoreBookingHindrance": false,
|
||||||
|
"examinationTypeId": 0,
|
||||||
|
"excludeExaminationCategories": [],
|
||||||
|
"rescheduleTypeId": 0,
|
||||||
|
"paymentIsActive": false,
|
||||||
|
"paymentReference": null,
|
||||||
|
"paymentUrl": null,
|
||||||
|
"searchedMonths": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMetadataEndpoint(req, res) {
|
||||||
|
// Check for the required parameters
|
||||||
|
if (!req.body || !req.body.licenceId || !req.body.ssn) {
|
||||||
|
res.status(400).json({ message: 'Missing required parameters' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ssn = req.body.ssn;
|
||||||
|
let licenceId = req.body.licenceId;
|
||||||
|
|
||||||
|
let body = METADATA_TEMPLATE
|
||||||
|
body.bookingSession.socialSecurityNumber = ssn
|
||||||
|
body.bookingSession.licenceId = licenceId
|
||||||
|
|
||||||
|
let response = await fetch(METADATA_ENDPOINT, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
res.status(500).json({ message: 'Something went wrong' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = await response.json()
|
||||||
|
// console.log(json)
|
||||||
|
|
||||||
|
res.json(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getMetadataEndpoint;
|
77
endpoint_handlers/occasions.js
Normal file
77
endpoint_handlers/occasions.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
const OCCASION_ENDPOINT = 'https://fp.trafikverket.se/boka/occasion-bundles'
|
||||||
|
|
||||||
|
const OCCASION_TEMPLATE = {
|
||||||
|
"bookingSession": {
|
||||||
|
"socialSecurityNumber": "",
|
||||||
|
"licenceId": 4,
|
||||||
|
"bookingModeId": 0,
|
||||||
|
"ignoreDebt": false,
|
||||||
|
"ignoreBookingHindrance": false,
|
||||||
|
"examinationTypeId": 0,
|
||||||
|
"excludeExaminationCategories": [],
|
||||||
|
"rescheduleTypeId": 0,
|
||||||
|
"paymentIsActive": true,
|
||||||
|
"paymentReference": null,
|
||||||
|
"paymentUrl": null,
|
||||||
|
"searchedMonths": 0
|
||||||
|
},
|
||||||
|
"occasionBundleQuery": {
|
||||||
|
"startDate": "1970-01-01T00:00:00.000Z",
|
||||||
|
"searchedMonths": 0,
|
||||||
|
"locationId": 1000060,
|
||||||
|
"nearbyLocationIds": [],
|
||||||
|
"languageId": 13,
|
||||||
|
"vehicleTypeId": 1,
|
||||||
|
"tachographTypeId": 1,
|
||||||
|
"occasionChoiceId": 1,
|
||||||
|
"examinationTypeId": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// "nearbyLocationIds": [1000121, 1000302, 1000047, 1000009, 1000096, 1000122, 1000066, 1000139, 1000077, 1000138, 1000317, 1000123, 1000069, 1000334, 1000106, 1000103, 1000012, 1000078, 1000318, 1000038, 1000005, 1000087, 1000130, 1000144],
|
||||||
|
|
||||||
|
async function getOccasionEndpoint(req, res) {
|
||||||
|
// Check for the required parameters
|
||||||
|
if (!req.body || !req.body.licenceId || !req.body.ssn || !req.body.locationId || !req.body.examType) {
|
||||||
|
res.status(400).json({ message: 'Missing required parameters' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ssn = req.body.ssn;
|
||||||
|
let licenceId = req.body.licenceId;
|
||||||
|
let locationId = req.body.locationId;
|
||||||
|
let nearbyIds = req.body.nearbyIds;
|
||||||
|
let examType = req.body.examType;
|
||||||
|
|
||||||
|
if (!locationId.length > 0) {
|
||||||
|
res.status(400).json({ message: 'Missing required parameters' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = OCCASION_TEMPLATE
|
||||||
|
body.bookingSession.socialSecurityNumber = ssn
|
||||||
|
body.bookingSession.licenceId = licenceId
|
||||||
|
body.occasionBundleQuery.locationId = locationId
|
||||||
|
body.occasionBundleQuery.nearbyLocationIds = nearbyIds
|
||||||
|
body.occasionBundleQuery.examinationTypeId = examType
|
||||||
|
|
||||||
|
console.log(body)
|
||||||
|
|
||||||
|
let response = await fetch(OCCASION_ENDPOINT, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
res.status(500).json({ message: 'Something went wrong' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = await response.json()
|
||||||
|
// console.log(json)
|
||||||
|
|
||||||
|
res.json(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getOccasionEndpoint;
|
34
endpoint_handlers/suggested.js
Normal file
34
endpoint_handlers/suggested.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const SUGGESTED_URL = 'https://fp.trafikverket.se/boka/get-suggested-reservations-by-licence-and-ssn'
|
||||||
|
|
||||||
|
async function getSuggestedEndpoint(req, res) {
|
||||||
|
// Check for the required parameters
|
||||||
|
if (!req.body || !req.body.licenceId || !req.body.ssn) {
|
||||||
|
res.status(400).json({ message: 'Missing required parameters' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ssn = req.body.ssn;
|
||||||
|
let licenceId = req.body.licenceId;
|
||||||
|
|
||||||
|
let response = await fetch(SUGGESTED_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
ssn: ssn,
|
||||||
|
licenceId: licenceId,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
res.status(500).json({ message: 'Something went wrong' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = await response.json()
|
||||||
|
console.log(json)
|
||||||
|
|
||||||
|
res.json(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = getSuggestedEndpoint;
|
|
@ -5,59 +5,39 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name"viewport" content="width=device-width, initial-scale=1.0">
|
<meta name"viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||||
<link rel="stylesheet" href="static/style.css">
|
<link rel="stylesheet" href="static/style.css">
|
||||||
<script src="static/script.js"></script>
|
<script src="static/script.js" defer></script>
|
||||||
<title>TFSearch</title>
|
<title>TFSearch</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<script>// To fix issue with forcing page before css is loaded...</script>
|
||||||
<div id="site-container">
|
<div id="site-container">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<h1>TFSearch</h1>
|
<h1>TFSearch</h1>
|
||||||
<p>Intuitiv sökning efter lediga uppkörningstider</p>
|
<p><b>Intuitiv sökning efter lediga uppkörningstider</b></p>
|
||||||
|
<p>Ingen personlig data samlas, analyseras eller delas.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="search-container">
|
<div id="search-container">
|
||||||
<input type="text" value="SSN" placeholder="Personnummer" size="12"></input>
|
<input id="ssn-input" type="text" pattern="[0-9]" placeholder="Personnummer" maxlength="12" size="12"
|
||||||
<select required name="Körkortstyp" required>
|
onkeyup="ssnChanged(this)" required></input>
|
||||||
<option value="A">Tung</option>
|
<select id="license-selector" required name="Körkortstyp" onchange="licenceChanged(this)" disabled>
|
||||||
<option value="A2">Lätt</option>
|
|
||||||
<option value="AM">Heaby</option>
|
|
||||||
</option>
|
|
||||||
</select>
|
</select>
|
||||||
<select required name="ort" required>
|
<select id="location-selector" required name="ort" onchange="locationChanged(this)" disabled>
|
||||||
<option value="Alla orter">Alla Orter</option>
|
<option value="all">Hela Sverige</option>
|
||||||
<option value="Halmstad">Halmstad</option>
|
|
||||||
<option value="Falkenberg">Falkenberg</option>
|
|
||||||
</option>
|
|
||||||
</select>
|
</select>
|
||||||
<button type="submit">Search</button>
|
<button id="searchButton" type="submit" onclick="executeSearch()" disabled>Search</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="results-container">
|
<div id="results-container">
|
||||||
<table>
|
<table id="results-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Kort</th>
|
<th>Kort</th>
|
||||||
<th>Pris</th>
|
<th>Pris</th>
|
||||||
<th>Datum</th>
|
<th>Datum</th>
|
||||||
|
<th>Tid</th>
|
||||||
<th>Länk</th>
|
<th>Länk</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>1</td>
|
|
||||||
<td>2</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>4</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1</td>
|
|
||||||
<td>2</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>4</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>1</td>
|
|
||||||
<td>2</td>
|
|
||||||
<td>3</td>
|
|
||||||
<td>4</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
21
index.js
21
index.js
|
@ -1,5 +1,10 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|
||||||
|
const getSuggestedEndpoint = require('./endpoint_handlers/suggested.js');
|
||||||
|
const getMetadataEndpoint = require('./endpoint_handlers/metadata.js');
|
||||||
|
const getOccasionsEndpoint = require('./endpoint_handlers/occasions.js');
|
||||||
|
const getLicenceInfo = require('./endpoint_handlers/licenseinfo.js');
|
||||||
|
|
||||||
// Read the port from the environment if possible
|
// Read the port from the environment if possible
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
@ -8,13 +13,25 @@ const server = express();
|
||||||
// Set up the static directory to server cssa and other assets
|
// Set up the static directory to server cssa and other assets
|
||||||
server.use('/static', express.static('static'));
|
server.use('/static', express.static('static'));
|
||||||
|
|
||||||
|
server.use(express.json());
|
||||||
|
server.use(
|
||||||
|
express.urlencoded({
|
||||||
|
extended: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Root path serves index
|
// Root path serves index
|
||||||
server.get('/', (req, res) => {
|
server.get('/', (req, res) => {
|
||||||
res.sendFile(__dirname + '/html/index.html');
|
res.sendFile(__dirname + '/html/index.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set up API endpoints
|
||||||
|
server.post('/suggested', getSuggestedEndpoint)
|
||||||
|
server.post('/metadata', getMetadataEndpoint)
|
||||||
|
server.post('/occasions', getOccasionsEndpoint)
|
||||||
|
server.post('/licenseinfo', getLicenceInfo)
|
||||||
|
|
||||||
// Listen and provide feedback
|
// Listen and provide feedback
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
console.log(`Server running on port ${port}`);
|
console.log(`Server running on port ${port}`);
|
||||||
}
|
});
|
||||||
);
|
|
317
static/script.js
317
static/script.js
|
@ -1 +1,318 @@
|
||||||
console.log("Javascript is executing properly...");
|
console.log("Javascript is executing properly...");
|
||||||
|
|
||||||
|
const QueryParams = {
|
||||||
|
SSN: "",
|
||||||
|
LicenseId: "",
|
||||||
|
LocationIds: [],
|
||||||
|
examType: "", // Unused for now
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppState = {
|
||||||
|
LocationsFetched: "",
|
||||||
|
SearchMessage: "",
|
||||||
|
SearchResults: [],
|
||||||
|
LocationIndex: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the state and the UI
|
||||||
|
async function clearState() {
|
||||||
|
AppState.SearchResults = [];
|
||||||
|
// AppState.LocationIndex = {};
|
||||||
|
// AppState.SearchMessage = "";
|
||||||
|
// searchResults.innerHTML = "";
|
||||||
|
resultsTable.innerHTML = "";
|
||||||
|
// locationSelector.innerHTML = "";
|
||||||
|
// locationSelector.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readState() {
|
||||||
|
clearState();
|
||||||
|
console.log("Checking state...")
|
||||||
|
if (ssnInput.value.length == 12 && !isNaN(ssnInput.value)) {
|
||||||
|
console.log("SSN is valid...")
|
||||||
|
QueryParams.SSN = ssnInput.value;
|
||||||
|
// if (!AppState.LocationsFetched)
|
||||||
|
await populateLicenses();
|
||||||
|
QueryParams.LicenseId = licenseSelector.value;
|
||||||
|
await populateLocations(await queryMetadata(QueryParams.SSN, QueryParams.LicenseId));
|
||||||
|
licenseSelector.disabled = false;
|
||||||
|
locationSelector.disabled = false;
|
||||||
|
} else {
|
||||||
|
// SSN was changed, but is not valid
|
||||||
|
QueryParams.SSN = "";
|
||||||
|
licenseSelector.disabled = true;
|
||||||
|
locationSelector.disabled = true;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (licenseSelector.value.length > 0 && licenseSelector.value != AppState.LocationsFetched) {
|
||||||
|
AppState.LocationsFetched = licenseSelector.value;
|
||||||
|
QueryParams.LicenseId = licenseSelector.value;
|
||||||
|
|
||||||
|
QueryParams.examType = (await querySuggested(QueryParams.SSN, QueryParams.LicenseId)).data[0].examinationTypeId;
|
||||||
|
|
||||||
|
// await populateLocations(await queryMetadata(QueryParams.SSN, QueryParams.LicenseId));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locationSelector.value.length > 0 && AppState.LocationsFetched) {
|
||||||
|
// console.log(locationSelector.value)
|
||||||
|
if (locationSelector.value == "all") {
|
||||||
|
QueryParams.LocationIds = Object.keys(AppState.LocationIndex)
|
||||||
|
} else {
|
||||||
|
QueryParams.LocationIds = [locationSelector.value];
|
||||||
|
}
|
||||||
|
// console.log(QueryParams)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
function readyForSearch() {
|
||||||
|
console.log("State is ready for search...")
|
||||||
|
return QueryParams.SSN.length == 12 && QueryParams.LicenseId.length > 0 && QueryParams.LocationIds.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseSelector = document.getElementById("license-selector");
|
||||||
|
const ssnInput = document.getElementById("ssn-input");
|
||||||
|
const locationSelector = document.getElementById("location-selector");
|
||||||
|
const searchButton = document.getElementById("searchButton");
|
||||||
|
const resultsTable = document.getElementById("results-table");
|
||||||
|
// const resultsContainer = document.getElementById("results-container");
|
||||||
|
|
||||||
|
async function executeSearch() {
|
||||||
|
console.log("Executing search...")
|
||||||
|
await readState()
|
||||||
|
console.log(QueryParams)
|
||||||
|
if (!readyForSearch()) {
|
||||||
|
console.log("Not ready for search...")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await querySeveralOccasions();
|
||||||
|
// console.log(AppState.SearchResults)
|
||||||
|
await displaySearchResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function displaySearchResults() {
|
||||||
|
// console.log(AppState.SearchResults)
|
||||||
|
console.log("Displaying search results...")
|
||||||
|
AppState.SearchResults.sort((a, b) => {
|
||||||
|
if (a.date < b.date) return -1;
|
||||||
|
if (a.date > b.date) return 1;
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
console.log(AppState.SearchResults)
|
||||||
|
resultsTable.innerHTML = "<tbody><tr> <th>Kort</th> <th>Ort</th> <th>Pris</th> <th>Datum</th> <th>Tid</th> <th>Länk</th> </tr></tbody>"
|
||||||
|
for (let occ of AppState.SearchResults) {
|
||||||
|
let tr = document.createElement("tr");
|
||||||
|
tr.className = "table-row";
|
||||||
|
let td_license = document.createElement("td");
|
||||||
|
let td_location = document.createElement("td");
|
||||||
|
let td_price = document.createElement("td");
|
||||||
|
let td_date = document.createElement("td");
|
||||||
|
let td_time = document.createElement("td");
|
||||||
|
let td_link = document.createElement("td");
|
||||||
|
|
||||||
|
td_license.innerText = occ.name;
|
||||||
|
td_location.innerText = occ.location;
|
||||||
|
td_price.innerText = occ.cost;
|
||||||
|
td_date.innerText = occ.date;
|
||||||
|
td_time.innerText = occ.time;
|
||||||
|
td_link.innerText = "-"
|
||||||
|
|
||||||
|
tr.appendChild(td_license);
|
||||||
|
tr.appendChild(td_location);
|
||||||
|
tr.appendChild(td_price);
|
||||||
|
tr.appendChild(td_date);
|
||||||
|
tr.appendChild(td_time);
|
||||||
|
tr.appendChild(td_link);
|
||||||
|
|
||||||
|
resultsTable.appendChild(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function querySuggested(ssn, licenseId) {
|
||||||
|
let msg = await (await fetch('/suggested', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
licenceId: licenseId,
|
||||||
|
ssn: ssn,
|
||||||
|
}),
|
||||||
|
})).json()
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// The metadata is specific to the license type
|
||||||
|
async function queryMetadata(ssn, licenseId) {
|
||||||
|
console.log("Getting metadata...")
|
||||||
|
let msg = await (await fetch('/metadata', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
licenceId: licenseId,
|
||||||
|
ssn: ssn,
|
||||||
|
}),
|
||||||
|
})).json()
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryOccasions() {
|
||||||
|
console.log("Querying occasions...")
|
||||||
|
let occasions = []
|
||||||
|
// console.log(QueryParams)
|
||||||
|
for (const locationId of QueryParams.LocationIds) {
|
||||||
|
let msg = await (await fetch('/occasions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
licenceId: QueryParams.LicenseId,
|
||||||
|
ssn: QueryParams.SSN,
|
||||||
|
locationId: locationId,
|
||||||
|
examType: QueryParams.examType,
|
||||||
|
}),
|
||||||
|
})).json()
|
||||||
|
if (!msg || !msg.data || !msg.data.bundles) continue;
|
||||||
|
for (let occasion of msg.data.bundles) {
|
||||||
|
occ = occasion.occasions[0];
|
||||||
|
|
||||||
|
occasions.push({
|
||||||
|
name: occ.name,
|
||||||
|
location: occ.locationName,
|
||||||
|
cost: occasion.cost,
|
||||||
|
date: occ.date,
|
||||||
|
time: occ.time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(occasions)
|
||||||
|
// return msg
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
AppState.locationResults = occasions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function querySeveralOccasions() {
|
||||||
|
console.log("Querying several occasions...")
|
||||||
|
i = 0
|
||||||
|
while (i < QueryParams.LocationIds.length) {
|
||||||
|
let current_array = QueryParams.LocationIds.slice(i, i + 4)
|
||||||
|
console.log(current_array)
|
||||||
|
let request = await (await fetch('/occasions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
licenceId: QueryParams.LicenseId,
|
||||||
|
ssn: QueryParams.SSN,
|
||||||
|
locationId: current_array[0], // The first
|
||||||
|
nearbyIds: current_array.slice(1), // The rest
|
||||||
|
examType: QueryParams.examType,
|
||||||
|
}),
|
||||||
|
})).json()
|
||||||
|
if (!request || !request.data || !request.data.bundles) continue;
|
||||||
|
let bundles = request.data.bundles
|
||||||
|
for (let occasion of bundles) {
|
||||||
|
let occ = occasion.occasions[0];
|
||||||
|
|
||||||
|
AppState.SearchResults.push({
|
||||||
|
name: occ.name,
|
||||||
|
location: occ.locationName,
|
||||||
|
cost: occasion.cost,
|
||||||
|
date: occ.date,
|
||||||
|
time: occ.time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryLicenseinfo() {
|
||||||
|
console.log("Querying license info...")
|
||||||
|
let msg = await (await fetch('/licenseinfo', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})).json()
|
||||||
|
return msg
|
||||||
|
// console.log(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// let selector = document.getElementById('license-selector')
|
||||||
|
async function populateLicenses() {
|
||||||
|
console.log("Populating licenses...")
|
||||||
|
let licenseinfo = await queryLicenseinfo()
|
||||||
|
|
||||||
|
// slice(0, 2) to only show the first two license types (car and motorcycle)
|
||||||
|
for (const license_cat of licenseinfo.data.licenceCategories.slice(0, 2)) {
|
||||||
|
for (const license of license_cat.licences) {
|
||||||
|
const new_option = document.createElement('option')
|
||||||
|
new_option.value = license.id
|
||||||
|
new_option.innerText = `${license.name} ${license.description}`
|
||||||
|
licenseSelector.appendChild(new_option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executed each time the license type is changed
|
||||||
|
async function licenceChanged(field) {
|
||||||
|
QueryParams.LicenseId = field.value
|
||||||
|
readState()
|
||||||
|
|
||||||
|
// let metadata_response = await querySuggested(QueryParams.SSN, QueryParams.LicenseId)
|
||||||
|
// if (!metadata_response.data[0]) {
|
||||||
|
// QueryParams.SearchMessage = "This license type is not available for this person."
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// QueryParams.examType = metadata_response.data[0].examinationTypeId
|
||||||
|
|
||||||
|
// console.log(QueryParams)
|
||||||
|
// let metadata = await queryMetadata(QueryParams.SSN, QueryParams.LicenseId)
|
||||||
|
// populateLocations(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function populateLocations(response_json) {
|
||||||
|
if (!response_json.data) {
|
||||||
|
console.log("No locations found, likely throttled")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const location of response_json.data.locations) {
|
||||||
|
// Populate the location index so that we can retrieve other data later
|
||||||
|
AppState.LocationIndex[location.location.id] = location
|
||||||
|
|
||||||
|
let name = location.location.name
|
||||||
|
let id = location.location.id
|
||||||
|
|
||||||
|
const new_option = document.createElement('option')
|
||||||
|
new_option.value = id
|
||||||
|
new_option.innerText = `${name}`
|
||||||
|
locationSelector.appendChild(new_option)
|
||||||
|
locationSelector.disabled = false
|
||||||
|
searchButton.disabled = false
|
||||||
|
// console.log(name, id)
|
||||||
|
// const new_option = document.createElement('option')
|
||||||
|
// new_option.value = location.id
|
||||||
|
// new_option.innerText = location.name
|
||||||
|
// locationSelector.appendChild(new_option)
|
||||||
|
}
|
||||||
|
// console.log(AppState.LocationIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function locationChanged(field) {
|
||||||
|
readState()
|
||||||
|
}
|
||||||
|
|
||||||
|
let ssn_input_element = document.getElementById('ssn-input')
|
||||||
|
async function ssnChanged(field) {
|
||||||
|
readState()
|
||||||
|
}
|
||||||
|
|
||||||
|
readState()
|
|
@ -29,9 +29,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container {
|
#search-container {
|
||||||
|
max-width: 800px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container input {
|
#search-container input {
|
||||||
|
@ -55,6 +57,12 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-container select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
#results-container {}
|
#results-container {}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
@ -66,7 +74,7 @@ th,
|
||||||
td {
|
td {
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 16px;
|
padding: 4px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
|
|
Loading…
Reference in a new issue