PageSourceSearch

https://kagoafrica.com/client/assets/js/register.js?version=3.0.9.1

js kagoafrica.com collected 2026-09-24 14:15:52 UTC 17,423 bytes, 592 lines download raw bytes

1console.log("Init register...");
2class PageState {
3  constructor() {
4    this.tabs = ["company-info", "personal-info", "documents"];
5    this.activeTab = "company-info";
6    this.companyInfoFields = {
7      "companyName": {
8        "name": "Company name",
9        "value": null,
10        "error": null
11      },
12      "tinNo": {
13        "name": "TIN number",
14        "value": null,
15        "error": null
16      },
17      "address": {
18        "name": "Address",
19        "value": null,
20        "error": null
21      },
22      "businessType": {
23        "name": "Business specialization",
24        "value": null,
25        "error": null
26      },
27      "no": {
28        "name": "Estimated volume",
29        "value": null,
30        "error": null
31      },
32      "no2": {
33        "name": "Estimated volume",
34        "value": null,
35        "error": null
36      }
37    };
38    this.personalInfoFields = {
39      "firstName": {
40        "name": "First name",
41        "value": null,
42        "error": null
43      },
44      "lastName": {
45        "name": "Last name",
46        "value": null,
47        "error": null
48      },
49      "position": {
50        "name": "Position",
51        "value": null,
52        "error": null
53      },
54      "email": {
55        "name": "Email",
56        "value": null,
57        "error": null
58      },
59      // "mobile": {
60      //   "name": "Phone number",
61      //   "value": null,
62      //   "error": null
63      // },
64      // "securityQuestions": {
65      //   "name": "Security questions",
66      //   "value": null,
67      //   "error": null
68      // },
69    };
70    this.documents = {
71      "crt": {
72        "value": null,
73        "error": null
74      },
75      "memo": {
76        "value": null,
77        "error": null
78      },
79      "tax": {
80        "value": null,
81        "error": null
82      },
83      "tin": {
84        "value": null,
85        "error": null
86      },
87      "businessLicense": {
88        "value": null,
89        "error": null
90      },
91      "insuranceNote": {
92        "value": null,
93        "error": null
94      },
95      "moa": {
96        "value": null,
97        "error": null
98      },
99      "aoa": {
100        "value": null,
101        "error": null
102      },
103      "acquisitionChannel": {
104        "value": null,
105        "error": null
106      },
107      "terms": {
108        "value": null,
109        "error": null
110      }
111    }
112    this.securityQuestions = {
113      1: "What is your favorite color?",
114      3: "What is your pet's name?",
115      4: "What was the name of your math teacher?",
116      5: "What was your childhood nickname?",
117      6: "What is the name of your favorite childhood friend?",
118    };
119    this.selectedSecurityQuestions = {};
120    this.maxFileSizeInMB = 5;
121    this.totalMaxFileSizeInMB = 15;
122    this.mergedDocument = null;
123  }
124
125  setActiveTab(tabId) {
126    if (!this.tabs.includes(tabId)) {
127      console.warn("tabId is invalid");
128      return;
129    }
130
131    this.activeTab = tabId;
132    this.tabs.forEach(tabId => {
133      $(`#${tabId}`).removeClass("active");
134    })
135    $(`#${this.activeTab}`).addClass("active");
136    $(`.nav-link`).removeClass("active");
137    $(`#${this.activeTab}-tab-btn`).addClass("active");
138  }
139
140  setSecurityQuestions(data) {
141    this.selectedSecurityQuestions = data;
142    this.renderSecurityQuestions();
143  }
144
145  renderSecurityQuestions() {
146    let htmlString = "";
147    $(".security-questions-table tbody").html(htmlString);
148    for (const [questionId, questionObj] of Object.entries(
149      this.selectedSecurityQuestions
150    )) {
151      htmlString += `
152        <tr data-row-id="${questionId}">
153          <td>${questionObj.question}</td>
154          <td class='q-answer'>****</td>
155          <td>
156            <button class="btn btn-sm bg-light text-dark me-2 view-btn show" data-question-id="${questionId}">show</button>
157            <button class="btn btn-sm bg-light text-dark remove-btn" data-question-id="${questionId}">remove</button>
158          </td>
159        </tr>
160        `;
161    }
162    $(".security-questions-table tbody").html(htmlString);
163  }
164}
165
166const pageState = new PageState();
167const questionSelectize = $("#question").selectize()[0].selectize;
168let mobileItiInstance = window.intlTelInput(document.getElementById("mobile"), {
169  // any initialisation options go here
170  initialCountry: "TZ",
171  formatOnDisplay: true,
172  utilsScript: true,
173  separateDialCode: true,
174  preferredCountries: ["KE", "UG", "TZ"],
175});
176
177// Initialize dropzone
178const mergedDropzone = new Dropzone("div.dropzone", {
179    url: "/upload-endpoint.php", // Your backend PHP upload endpoint
180    autoProcessQueue: false,
181    paramName: "merged_document", // Field name sent to the server
182    maxFilesize: 5, // Maximum file size in MB
183    maxFiles: 1, // Only accept 1 single merged file
184    acceptedFiles: ".pdf,application/pdf",
185    addRemoveLinks: true,
186    dictDefaultMessage: "<strong>Have a single PDF document?</strong><br>Drop file here or click to upload",
187    
188    init: function () {
189      this.on("addedfile", function (file) {
190        // Enforce single file constraint: replace old file if new one is added
191        if (this.files.length > 1) {
192          this.removeFile(this.files[0]);
193        }
194
195        // Auto-assign the single file ID to all 6 hidden document inputs
196        document.querySelectorAll(".individual-doc-input").forEach((input) => {
197          // console.log(input);
198          // input.files = this.files[0];
199          input.setAttribute("disabled", true);
200          input.setAttribute("readonly", true);
201          console.log("Input Disabled");
202        });
203
204        pageState.mergedDocument = file;
205        document.getElementById("individual-document-block").style.display = "flex";
206      });
207
208      this.on("success", function (file, response) {
209        // Parse server response (e.g., uploaded file ID)
210        const fileData = typeof response === "string" ? JSON.parse(response) : response;
211        
212        // Auto-assign the single file ID to all 6 hidden document inputs
213        document.querySelectorAll(".individual-doc-input").forEach((input) => {
214          console.log(input);
215          input.value = fileData.file_id;
216          input.setAttribute("disabled", true);
217        });
218      });
219
220      this.on("removedfile", function () {
221        // Reset individual references if user removes the merged PDF
222        document.querySelectorAll(".individual-doc-input").forEach((input) => {
223          input.removeAttribute("readonly");
224          input.removeAttribute("disabled");
225        });
226
227        document.getElementById("individual-document-block").style.display = "none";
228      });
229    }
230  });
231
232function resetCompanyInfoFields() {
233  for (const fieldId in pageState.companyInfoFields) {
234    pageState.companyInfoFields[fieldId].error = null;
235    $(`.error.${fieldId}`).addClass("d-none");
236  }
237}
238
239function validateCompanyInfo() {
240  let isValid = true;
241  resetCompanyInfoFields();
242  for (const fieldId in pageState.companyInfoFields) {
243    let fieldValue = $(`#${fieldId}`).val();
244    if (!fieldValue) {
245      pageState.companyInfoFields[fieldId].error = pageState.companyInfoFields[fieldId].name + " is required!";
246      $(`.error.${fieldId}`).text(pageState.companyInfoFields[fieldId].error);
247      $(`.error.${fieldId}`).removeClass("d-none");
248      isValid = false;
249    }
250
251    else {
252      pageState.companyInfoFields[fieldId].value = fieldValue;
253    }
254  }
255
256  return isValid;
257}
258
259function resetPersonaInfoFields() {
260  for (const fieldId in pageState.personalInfoFields) {
261    pageState.personalInfoFields[fieldId].error = null;
262    $(`.error.${fieldId}`).addClass("d-none");
263  }
264}
265
266function validatePersonalInfo() {
267  let isValid = true;
268  resetPersonaInfoFields();
269  for (const fieldId in pageState.personalInfoFields) {
270    let fieldValue = $(`#${fieldId}`).val();
271    if (!fieldValue) {
272      pageState.personalInfoFields[fieldId].error = pageState.personalInfoFields[fieldId].name + " is required!";
273      $(`.error.${fieldId}`).text(pageState.personalInfoFields[fieldId].error);
274      $(`.error.${fieldId}`).removeClass("d-none");
275      isValid = false;
276    }
277
278    else {
279      pageState.personalInfoFields[fieldId].value = fieldValue;
280    }
281  }
282
283  return isValid;
284}
285
286function resetDocumentsError() {
287  $(".error.crt").addClass("d-none");
288  $(".error.memo").addClass("d-none");
289  $(".error.tax").addClass("d-none");
290  $(".error.tin").addClass("d-none");
291  $(".error.businessLicense").addClass("d-none");
292  $(".error.insuaranceNote").addClass("d-none");
293  $(".error.moa").addClass("d-none");
294  $(".error.aoa").addClass("d-none");
295  $(".error.terms").addClass("d-none");
296  $(".acquisitionChannel.error").addClass("d-none");
297}
298
299function validateDocuments() {
300  let isValid = true;
301
302  resetDocumentsError();
303
304  let crt = $("#crt").prop("files")[0];
305  let brela = $("#memo").prop("files")[0];
306  let tax = $("#tax").prop("files")[0];
307  let tin = $("#tin").prop("files")[0];
308  let businessLicense = $("#businessLicense").prop("files")[0];
309  let insuaranceNote = $("#insuaranceNote").prop("files")[0];
310  let moa = $("#moa").prop("files")[0];
311  let aoa = $("#aoa").prop("files")[0];
312
313  if (!crt) {
314    $(".error.crt").removeClass("d-none");
315    isValid = false;
316  }
317
318  if (!brela) {
319    $(".error.memo").removeClass("d-none");
320    isValid = false;
321  }
322
323  if (!tax) {
324    $(".error.tax").removeClass("d-none");
325    isValid = false;
326  }
327
328  if (!tin) {
329    $(".error.tin").removeClass("d-none");
330    isValid = false;
331  }
332
333  if (!businessLicense) {
334    $(".error.businessLicense").removeClass("d-none");
335    isValid = false;
336  }
337
338  if (!insuaranceNote) {
339    $(".error.insuaranceNote").removeClass("d-none");
340    isValid = false;
341  }
342
343  if (!moa) {
344    $(".error.moa").removeClass("d-none");
345    isValid = false;
346  }
347
348  if (!aoa) {
349    $(".error.aoa").removeClass("d-none");
350    isValid = false;
351  }
352
353  if (crt && crt.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
354    $('.error.crt').text('The file upload cannot exceed 5MB');
355    $('.error.crt').removeClass('d-none');
356    isValid = false;
357  }
358
359  if (brela && brela.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
360    $('.error.memo').text('The file upload cannot exceed 5MB');
361    $('.error.memo').removeClass('d-none');
362    isValid = false;
363  }
364
365  if (tax && tax.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
366    $('.error.tax').text('The file upload cannot exceed 5MB');
367    $('.error.tax').removeClass('d-none');
368    isValid = false;
369  }
370
371  if (tin && tin.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
372    $('.error.tin').text('The file upload cannot exceed 5MB');
373    $('.error.tin').removeClass('d-none');
374    isValid = false;
375  }
376
377  if (businessLicense && businessLicense.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
378    $('.error.businessLicense').text('The file upload cannot exceed 5MB');
379    $('.error.businessLicense').removeClass('d-none');
380    isValid = false;
381  }
382
383  if (insuaranceNote && insuaranceNote.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
384    $('.error.insuaranceNote').text('The file upload cannot exceed 5MB');
385    $('.error.insuaranceNote').removeClass('d-none');
386    isValid = false;
387  }
388
389  if (moa && moa.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
390    $('.error.moa').text('The file upload cannot exceed 5MB');
391    $('.error.moa').removeClass('d-none');
392    isValid = false;
393  }
394
395  if (aoa && aoa.size / (1024 * 1024) > pageState.maxFileSizeInMB) {
396    $('.error.aoa').text('The file upload cannot exceed 5MB');
397    $('.error.aoa').removeClass('d-none');
398    isValid = false;
399  }
400
401  if (!$("#terms").is(":checked")) {
402    $(".error.terms").removeClass("d-none");
403    isValid = false;
404  }
405
406  if (!$("#acquisitionChannel").val()) {
407    $(".acquisitionChannel.error").removeClass("d-none");
408    isValid = false;
409  }
410
411  return isValid;
412}
413
414$("#company-info .next-btn").on("click", () => {
415  if (!validateCompanyInfo()) return;
416  pageState.setActiveTab("personal-info");
417})
418
419$("#personal-info .next-btn").on("click", () => {
420  $(".error.mobile").addClass("d-none");
421  $(".error.questions").addClass("d-none");
422  if (!validatePersonalInfo()) return;
423  if (!mobileItiInstance.isValidNumber()) {
424    $(".error.mobile").removeClass("d-none");
425    return;
426  }
427  if (Object.keys(pageState.selectedSecurityQuestions).length < 3) {
428    $(".error.questions").removeClass("d-none");
429    return;
430  }
431  pageState.setActiveTab("documents");
432})
433
434// Handle Security Questions
435$("#add-sec-btn").on("click", (e) => {
436  let question = questionSelectize.getValue();
437  let answer = $("#answer").val();
438
439  if (!question || !answer) {
440    return;
441  }
442
443  if (pageState.selectedSecurityQuestions[question]) {
444    return;
445  }
446
447  pageState.selectedSecurityQuestions[question] = {
448    question: pageState.securityQuestions[question],
449    answer: answer,
450  };
451
452  questionSelectize.setValue("");
453  $("#answer").val("");
454
455  pageState.setSecurityQuestions(pageState.selectedSecurityQuestions);
456});
457
458$(".security-questions-table tbody").on("click", ".view-btn", (e) => {
459  const questionId = e.target.dataset.questionId;
460  const action = e.target.classList.contains("show") ? "show" : "hide";
461  if (action == "show") {
462    $(`tr[data-row-id="${questionId}"]`)
463      .find(".q-answer")
464      .html(pageState.selectedSecurityQuestions[questionId].answer);
465    e.target.classList.replace("show", "hide");
466    e.target.textContent = "hide";
467  } else {
468    $(`tr[data-row-id="${questionId}"]`).find(".q-answer").html("****");
469    e.target.classList.replace("hide", "show");
470    e.target.textContent = "show";
471  }
472});
473
474$(".security-questions-table tbody").on("click", ".remove-btn", (e) => {
475  const questionId = e.target.dataset.questionId;
476  delete pageState.selectedSecurityQuestions[questionId];
477  pageState.setSecurityQuestions(pageState.selectedSecurityQuestions);
478});
479
480// Handle Submit
481$("#submit-btn").on("click", (e) => {
482  let isValid =
483    validateCompanyInfo() && validatePersonalInfo();
484
485  if (!pageState.mergedDocument && !validateDocuments()) {
486    return;
487  }
488
489  $(".error.terms").addClass("d-none");
490  $(".error.acquisitionChannel").addClass("d-none");
491  if (!$("#terms").is(":checked")) {
492    $(".error.terms").removeClass("d-none");
493    isValid = false;
494  }
495
496  if (!$("#acquisitionChannel").val()) {
497    $(".error.acquisitionChannel").removeClass("d-none");
498    isValid = false;
499  }
500
501  if (!isValid) return;
502
503  let loader = document.createElement("div");
504  loader.classList.add("spinner", "spinner-grow", "spinner-grow-sm", "ms-2");
505  e.target.append(loader);
506  e.target.setAttribute("disabled", true);
507
508  // Get Data
509  const formattedSecurityQuestions = {};
510  for (const index in pageState.selectedSecurityQuestions) {
511    formattedSecurityQuestions[pageState.selectedSecurityQuestions[index]['question']] = pageState.selectedSecurityQuestions[index]['answer'];
512  }
513  const data = {
514    appType: "signUp",
515    firstName: $("#firstName").val(),
516    lastName: $("#lastName").val(),
517    position: $("#position").val(),
518    email: $("#email").val(),
519    mobile: mobileItiInstance.getNumber(),
520    security: JSON.stringify(formattedSecurityQuestions),
521    companyName: $("#companyName").val(),
522    tinNo: $("#tinNo").val(),
523    address: $("#address").val(),
524    businessType: $("#businessType").val(),
525    no: $("#no").val(),
526    no2: $("#no2").val(),
527    acquisitionChannel: $("#acquisitionChannel").val()
528  };
529
530  let totalFileSizeInBytes = 0;
531  if (!pageState.mergedDocument) {
532    data.crt = $("#crt").prop("files")[0];
533    data.memo = $("#memo").prop("files")[0];
534    data.tax = $("#tax").prop("files")[0];
535    data.tin = $("#tin").prop("files")[0];
536    data.businessLicense = $("#businessLicense").prop("files")[0];
537    data.insuaranceNote = $("#insuaranceNote").prop("files")[0];
538    data.moa = $("#moa").prop("files")[0];
539    data.aoa = $("#aoa").prop("files")[0];
540    totalFileSizeInBytes = (data.crt.size + data.memo.size + data.tax.size);
541  }
542
543  else {
544    data.singleDocumentUpload = true;
545    data.mergedDocument = pageState.mergedDocument;
546  }
547  
548  const totalFileSizeInMB = (totalFileSizeInBytes / (1024 * 1024)).toFixed(2);
549  if (totalFileSizeInMB > pageState.totalMaxFileSizeInMB) {
550    swal("Warning", "The total file size of the 3 attached documents exceed the limit of 15MB (5MB per file)", "warning");
551    return;
552  }
553
554  // Post Data
555  postData(data, (json = false), (auth = false))
556    .then((res) => {
557      if (res.status == "failed") {
558        swal("Failed registration", res.message, "warning");
559      } else {
560        swal(
561          "Success",
562          "This application will undergo review and you will receive an email",
563          "success"
564        );
565
566        // Clear form after submission
567        $("input, select, textarea").val("");
568        questionSelectize.clear();
569        mobileItiInstance.setNumber("");
570        pageState.setSecurityQuestions({});
571        mergedDropzone.removeAllFiles(true);
572        $("#terms").prop("checked", false);
573        document.querySelectorAll(".individual-doc-input").forEach((input) => {
574          input.value = "";
575          input.removeAttribute("readonly");
576          input.removeAttribute("disabled");
577        });
578        resetCompanyInfoFields();
579        resetPersonaInfoFields();
580        resetDocumentsError();
581        pageState.setActiveTab("company-info");
582        document.getElementById("individual-document-block").style.display = "none";
583      }
584    })
585    .catch(error => {
586      swal("Error", error.message, "error");
587    })
588    .finally(() => {
589      loader.remove();
590      e.target.removeAttribute("disabled");
591    });
592});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.