diff --git a/apps/home/static/home/js/modals.js b/apps/home/static/home/js/modals.js
new file mode 100644
index 0000000..2d6d476
--- /dev/null
+++ b/apps/home/static/home/js/modals.js
@@ -0,0 +1,85 @@
+
+const validateBootstrapStyle = style => {
+ if (!["danger", "success", "warning", "info", "primary", "secondary"].includes(style)) {
+ throw new Error(`${style} is not a valid style`);
+ }
+ return true;
+}
+
+
+const arrayToHtmlList = (array, bold=false) => {
+ $ul = $("
").addClass("mb-0");
+
+ array.forEach(item => {
+ let $li = $("- ");
+ $ul.append(bold ? $li.append($("").text(item)) : $li.text(item));
+ });
+
+ return $ul;
+}
+
+
+const createModal = async (options = {}) => {
+ let $modal = $("#customModal");
+
+ let defaults = {
+ title: "Modal Title",
+ texts: [
+ {
+ content: "This is a modal",
+ html: false
+ }
+ ],
+ buttons: [
+ {
+ text: "Okay",
+ className: "btn-primary",
+ iconClass: "",
+ tabIndex: 2,
+ closeModal: true,
+ onClick: null
+ }
+ ]
+ };
+
+ let settings = { ...defaults, ...options };
+
+ $modal.find(".modal-title").text(settings.title);
+
+ // Texts
+ let $body = $modal.find(".modal-body").empty();
+
+ settings.texts.forEach((text, idx) => {
+ if (text.html) {
+ $body.append(text.content);
+ return;
+ }
+
+ let $para = $("
", {
+ text: text.content,
+ class: idx + 1 === settings.texts.length ? "mb-0" : ""
+ });
+ $body.append($para);
+ });
+
+ // Buttons
+ let $footer = $modal.find(".modal-footer").empty();
+
+ settings.buttons.forEach(button => {
+ let $btn = $("