Public Access
The owner asked for a plain feedback form: no Upwork name, no seat claim, and the freelancer-portal link visible on the page. The seat-claim layer is removed whole. - remove the GET /webhook/feedback seat-count read, its parsing and the four states it drove (available / claimed / full / count-unavailable) — one state now, the form - remove the claim POST, the 1-hour hold and its clock-time copy, the leftKeys contract, the count-retry button and the cohort-full branch - no capacity wording: seat/spot/claim/hold/cohort/full are gone, and "unlimited" is not written either — the page says nothing about capacity - the form posts the answers only: no upwork, no email, no identifier - progress bar is two steps (1 Sign up - 2 Give feedback); step 1 stays current because the page cannot honestly detect that the portal link was used - the freelancer-portal link is visible next to the intro and again in step 1's copy, new window with rel=noopener noreferrer and it says so in its accessible name Nothing on load is fetched: 0 requests to the webhook until a real submit.
504 lines
23 KiB
HTML
504 lines
23 KiB
HTML
<!doctype html>
|
|
<html lang="en-US">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Freelancer signup feedback — ODOO4projects</title>
|
|
<meta name="description" content="Tell us how the ODOO4projects freelancer signup went — every answer helps us improve the process before the directory opens." />
|
|
|
|
<!-- Private utility page. It is reached ONLY by the link we send, never by search.
|
|
noindex+nofollow here, absent from sitemap.xml and llms.txt, and linked from nowhere
|
|
on the site. See [[draft-page-convention]] for the same five rule. -->
|
|
<meta name="robots" content="noindex, nofollow" />
|
|
<!-- Nothing in this page's address is a credential, but the page is private and the
|
|
feedback is a person's words: keep the URL out of any third party's logs. -->
|
|
<meta name="referrer" content="no-referrer" />
|
|
<link rel="canonical" href="https://odoo4projects.com/feedback/" />
|
|
<meta property="og:url" content="https://odoo4projects.com/feedback/" />
|
|
<meta property="og:title" content="Freelancer signup feedback — ODOO4projects" />
|
|
<meta property="og:description" content="Tell us how the ODOO4projects freelancer signup went — every answer helps us improve the process." />
|
|
<meta property="og:type" content="website" />
|
|
<link rel="icon" href="/images/favicon.ico" />
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
|
media="print"
|
|
onload="this.media='all'"
|
|
/>
|
|
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
|
<link rel="stylesheet" href="/style.css?v=061517baef" />
|
|
|
|
<style>
|
|
/* Utility page, same shell as /freelancer-edit/ and the top bar of
|
|
/odoo-community-developers/: brand line, one card, the site tokens (:root in style.css)
|
|
and the CI palette only. No hero, no footer, no site chrome beyond the brand line. */
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
background: var(--cream);
|
|
color: var(--ink);
|
|
font-family: Inter, "Segoe UI", sans-serif;
|
|
line-height: 1.6;
|
|
}
|
|
.wrap { width: 86%; max-width: 1200px; margin: 0 auto; }
|
|
.topbar { background: var(--midnight); border-bottom: 1px solid var(--line-brass); padding: 0.85rem 0; }
|
|
.brand {
|
|
font-family: Marcellus, Georgia, serif;
|
|
font-size: 1.15rem;
|
|
letter-spacing: 0.04em;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
}
|
|
.brand span { color: var(--brass); }
|
|
main { padding: 2.5rem 0 4rem; }
|
|
.card-wrap { max-width: 760px; margin: 0 auto; }
|
|
h1 {
|
|
font-family: Marcellus, Georgia, serif;
|
|
font-weight: 400;
|
|
font-size: clamp(1.5rem, 4vw, 2.2rem);
|
|
letter-spacing: 0.02em;
|
|
margin: 0 0 0.4rem;
|
|
}
|
|
.lede { color: var(--ink-soft); margin: 0 0 1rem; }
|
|
.panel {
|
|
background: var(--ivory);
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius-lg);
|
|
padding: 1.5rem;
|
|
box-shadow: var(--shadow-rest);
|
|
}
|
|
.panel + .panel { margin-top: 1.25rem; }
|
|
h2 {
|
|
font-family: Marcellus, Georgia, serif;
|
|
font-weight: 400;
|
|
font-size: 1.15rem;
|
|
letter-spacing: 0.02em;
|
|
margin: 0 0 0.6rem;
|
|
}
|
|
.state { margin: 0; font-weight: 500; }
|
|
.state-warn, .state-err { color: var(--brass-deep); }
|
|
.state-ok { color: var(--success); }
|
|
.detail { margin: 0.5rem 0 0; font-size: 0.9rem; color: var(--ink-soft); }
|
|
|
|
/* ---- Forms ---- */
|
|
.field { margin: 0 0 1.1rem; }
|
|
.field > label { display: block; font-weight: 600; font-size: 0.9rem; margin: 0 0 0.35rem; }
|
|
input[type="text"], input[type="email"], textarea, select {
|
|
width: 100%;
|
|
font: inherit;
|
|
padding: 0.6rem 0.7rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: var(--radius);
|
|
background: #fff;
|
|
color: var(--ink);
|
|
}
|
|
textarea { resize: vertical; }
|
|
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible,
|
|
input[type="radio"]:focus-visible, input[type="checkbox"]:focus-visible {
|
|
outline: 2px solid var(--brass);
|
|
outline-offset: 1px;
|
|
}
|
|
.hint { font-size: 0.82rem; color: var(--ink-soft); margin: 0.35rem 0 0; }
|
|
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.9rem 1rem 0.4rem; margin: 0 0 1.1rem; }
|
|
legend { font-weight: 600; font-size: 0.9rem; padding: 0 0.35rem; }
|
|
.choice { display: flex; align-items: flex-start; gap: 0.55rem; margin: 0 0 0.5rem; font-size: 0.9rem; }
|
|
.choice input { margin-top: 0.28rem; flex: 0 0 auto; }
|
|
.field[data-bad="1"] input, .field[data-bad="1"] textarea, .field[data-bad="1"] select,
|
|
fieldset[data-bad="1"] { border-color: var(--brass-deep); }
|
|
.err { font-size: 0.82rem; color: var(--brass-deep); font-weight: 600; margin: 0.35rem 0 0; }
|
|
|
|
.btn {
|
|
display: inline-block;
|
|
font-family: Marcellus, Georgia, serif;
|
|
font-size: 0.9rem;
|
|
letter-spacing: 0.04em;
|
|
border: 0;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--brass);
|
|
color: var(--midnight);
|
|
padding: 0.7rem 1.5rem;
|
|
cursor: pointer;
|
|
}
|
|
.btn:hover { background: var(--brass-bright); }
|
|
.btn:focus-visible { outline: 2px solid var(--midnight); outline-offset: 2px; }
|
|
.btn[disabled] { opacity: 0.6; cursor: default; }
|
|
.status { margin: 0.9rem 0 0; font-weight: 500; min-height: 1.2em; }
|
|
.status.state-warn, .status.state-err { color: var(--brass-deep); }
|
|
.status.state-ok { color: var(--success); }
|
|
|
|
/* ---- Progress bar (two steps) ---- */
|
|
.progress { margin: 0 0 1.15rem; }
|
|
.steps-bar {
|
|
list-style: none;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.3rem 0.6rem;
|
|
margin: 0;
|
|
padding: 0;
|
|
font-size: 0.85rem;
|
|
}
|
|
.steps-bar .step { display: flex; align-items: center; gap: 0.4rem; color: var(--ink-soft); }
|
|
.steps-bar .step + .step::before { content: "·"; margin-right: 0.6rem; color: var(--line-brass); }
|
|
.step-mark {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 1.55rem;
|
|
height: 1.55rem;
|
|
border-radius: 999px;
|
|
border: 1px solid var(--line);
|
|
background: #fff;
|
|
font-size: 0.8rem;
|
|
line-height: 1;
|
|
}
|
|
/* The current step is the brass pill and the bolder label, and it is said out loud
|
|
("(current step)", .vh below) — weight and a word, so it is never colour alone. */
|
|
.steps-bar .step-current { color: var(--ink); font-weight: 600; }
|
|
.steps-bar .step-current .step-mark { background: var(--brass); border-color: var(--brass); color: var(--midnight); }
|
|
.link-signup { color: var(--brass-deep); font-weight: 600; }
|
|
/* Visually hidden, still read aloud. */
|
|
.vh {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
margin: -1px;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
clip: rect(0 0 0 0);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
</style>
|
|
|
|
<!-- The one wire name and shape this page uses, in ONE place. POST only — the page reads
|
|
nothing on load. SHAPE (match this in the n8n workflow):
|
|
|
|
POST submitUrl { "form": "feedback", <one key per question, the answer> }
|
|
-> any 2xx = receipt shown; a non-2xx is reported as a failure, never as success.
|
|
|
|
The body carries the answers and nothing else: no name, no email, no identifier of any
|
|
kind. An unexpected shape is named, never guessed. -->
|
|
<script>
|
|
window.O4F = {
|
|
// The one route that receives the feedback form.
|
|
submitUrl: "https://n8n.odoo4projects.com/webhook/feedback"
|
|
};
|
|
</script>
|
|
|
|
<!-- Privacy-friendly analytics by Plausible (verbatim; the page carries no query). -->
|
|
<script async src="https://plausible.office.odoo4projects.com/js/pa-NhA7Rf-79VopXFQXhSS4e.js"></script>
|
|
<script>
|
|
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
|
plausible.init()
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<header class="topbar">
|
|
<div class="wrap">
|
|
<a class="brand" href="https://odoo4projects.com/">ODOO<span>4</span>projects</a>
|
|
</div>
|
|
</header>
|
|
|
|
<main>
|
|
<div class="wrap">
|
|
<div class="card-wrap">
|
|
<h1>Freelancer signup feedback</h1>
|
|
<p class="lede">
|
|
We opened a free freelancer portal on ODOO4projects.com. Sign up there, then tell us how
|
|
it went — every answer helps us improve the process.
|
|
</p>
|
|
<!-- The portal link, visible next to the intro and not buried in step copy. It opens in
|
|
a new window and says so. It is a plain link, not the page's primary action —
|
|
the feedback form still is. -->
|
|
<p class="detail">
|
|
The directory opens on <strong>1 December</strong>. Signing up is free for freelancers
|
|
and clients, and the feedback you give here is what we fix before then.
|
|
<a
|
|
class="link-signup"
|
|
href="https://odoo4projects.com/odoo-community-developers/#apply"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>Sign up on the freelancer portal (opens in a new window)</a>.
|
|
</p>
|
|
|
|
<!-- Filled by the script at the foot of the page. Empty on purpose: with JavaScript off
|
|
there is no form to render, so an empty container plus the noscript note below is
|
|
the honest picture. -->
|
|
<div id="app"></div>
|
|
|
|
<noscript>
|
|
<div class="panel">
|
|
<p class="state state-warn">This page needs JavaScript to show the feedback form.</p>
|
|
<p class="detail">
|
|
Turn JavaScript on in your browser and open this page again — or reply to the message
|
|
that brought you here.
|
|
</p>
|
|
</div>
|
|
</noscript>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
(function () {
|
|
var C = window.O4F;
|
|
var app = document.getElementById("app");
|
|
// The application form on the directory page — the anchor the page's own "Get listed"
|
|
// triggers use. There is no separate login or account page, so this is the one target.
|
|
var PORTAL_URL = "https://odoo4projects.com/odoo-community-developers/#apply";
|
|
|
|
function el(tag, cls, text) {
|
|
var n = document.createElement(tag);
|
|
if (cls) n.className = cls;
|
|
if (text != null) n.textContent = text; // textContent only: a reply is never markup
|
|
return n;
|
|
}
|
|
function show(nodes) {
|
|
while (app.firstChild) app.removeChild(app.firstChild);
|
|
for (var i = 0; i < nodes.length; i++) app.appendChild(nodes[i]);
|
|
return nodes;
|
|
}
|
|
function status(text, kind) {
|
|
var p = el("p", "status" + (kind ? " state-" + kind : ""), text);
|
|
p.setAttribute("role", "status");
|
|
p.setAttribute("aria-live", "polite");
|
|
return p;
|
|
}
|
|
function fetchJson(url, opts) {
|
|
return fetch(url, opts).then(function (r) {
|
|
return r.text().then(function (t) {
|
|
var body = null;
|
|
try { body = JSON.parse(t); } catch (e) { body = null; }
|
|
return { ok: r.ok, status: r.status, body: body };
|
|
});
|
|
});
|
|
}
|
|
function msgOf(body) {
|
|
if (!body || typeof body !== "object") return "";
|
|
var m = body.message || body.error || body.detail;
|
|
return typeof m === "string" ? m : "";
|
|
}
|
|
// A link to the freelancer portal. Opens in a new window and says so, so a screen-reader
|
|
// user is not surprised by a new tab.
|
|
function portalLink() {
|
|
var p = el("p", "detail");
|
|
var a = el("a", "link-signup");
|
|
a.href = PORTAL_URL;
|
|
a.target = "_blank";
|
|
a.rel = "noopener noreferrer";
|
|
a.textContent = "Sign up on the freelancer portal (opens in a new window)";
|
|
p.appendChild(a);
|
|
return p;
|
|
}
|
|
|
|
// ---- Progress bar (two steps) ---------------------------------------------------------
|
|
// Step 1 is the signup on the portal, step 2 is this form. The page has no honest way to
|
|
// know the visitor has used the portal link, so step 1 stays current and nothing is
|
|
// guessed: the number, the bolder label and the spoken "(current step)" say which one is
|
|
// current, so it is never colour alone.
|
|
var STEP_LABELS = ["Sign up", "Give feedback"];
|
|
function progressBar(current) {
|
|
var nav = el("nav", "progress");
|
|
nav.setAttribute("aria-label", "Progress");
|
|
var ol = el("ol", "steps-bar");
|
|
STEP_LABELS.forEach(function (label, i) {
|
|
var n = i + 1;
|
|
var li = el("li", "step");
|
|
var mark = el("span", "step-mark");
|
|
mark.setAttribute("aria-hidden", "true");
|
|
mark.textContent = String(n);
|
|
li.appendChild(mark);
|
|
li.appendChild(el("span", "step-label", label));
|
|
if (n === current) {
|
|
li.className = "step step-current";
|
|
li.setAttribute("aria-current", "step");
|
|
li.appendChild(el("span", "vh", " (current step)"));
|
|
} else {
|
|
li.className = "step step-next";
|
|
}
|
|
ol.appendChild(li);
|
|
});
|
|
nav.appendChild(ol);
|
|
return nav;
|
|
}
|
|
|
|
// ---- Step 1 — the portal link, again, in the step's own copy -------------------------
|
|
function signupPanel() {
|
|
var box = el("div", "panel");
|
|
box.appendChild(el("h2", "", "Step 1 — sign up on the freelancer portal"));
|
|
box.appendChild(el("p", "detail",
|
|
"Create your free freelancer account and add your profile. The directory opens on 1 December."));
|
|
box.appendChild(portalLink());
|
|
return box;
|
|
}
|
|
|
|
// ---- The feedback form ----------------------------------------------------------------
|
|
// The n8n form's questions, with the copy corrected. The identity block (name, email,
|
|
// anonymous tick) and the publish-consent question are gone — do not bring them back.
|
|
var FIELDS = [
|
|
{ id: "finalized", label: "Did you finalize the signup?", type: "select", options: [["yes", "Yes"], ["no", "No"]], required: true },
|
|
{ id: "difficulty", label: "How hard was the signup?", type: "select", options: [["easy", "Easy"], ["ok", "OK"], ["hard", "Hard"]], required: true },
|
|
{ id: "signup_feedback", label: "What is your feedback on the signup?", type: "textarea", required: true },
|
|
{ id: "understood_scale", label: "Did you understand how we ask you to rate your skills? (the 15-point scale)", type: "select", options: [["yes", "Yes"], ["no", "No"]], required: true },
|
|
{ id: "scale_feedback", label: "What is your feedback on the 15-point skill scale?", type: "textarea", required: true },
|
|
{ id: "almost_stopped", label: "What almost stopped you from signing up?", type: "textarea", required: true, hint: "If nothing did, say so." },
|
|
{ id: "broke_or_confused", label: "Did anything break or confuse you?", type: "textarea", required: true },
|
|
{ id: "design_shows_work", label: "Do you think our profile design shows what you do well?", type: "select", options: [["yes", "Yes"], ["so-so", "So-so"], ["no", "No"]], required: true },
|
|
{ id: "design_feedback", label: "What can we improve about the profile design?", type: "textarea", required: true },
|
|
{ id: "will_stay", label: "Will you stay on the platform?", type: "select", options: [["yes", "Yes"], ["no", "No"]], required: true },
|
|
{ id: "improve_offer", label: "How can we improve what we offer you?", type: "textarea", required: true },
|
|
{ id: "recommend", label: "Would you recommend this platform to a freelance colleague?", type: "select", options: [["yes", "Yes, good idea"], ["maybe", "Maybe"], ["no", "Preferably not"]], required: true },
|
|
{ id: "expect_next", label: "What do you expect to happen next — and how soon?", type: "textarea", required: true }
|
|
];
|
|
|
|
function fieldBlock(spec) {
|
|
var f = el("div", "field");
|
|
f.setAttribute("data-field", spec.id);
|
|
if (spec.type === "radio") {
|
|
var fs = el("fieldset");
|
|
fs.setAttribute("data-field", spec.id);
|
|
var lg = el("legend", "", spec.label);
|
|
fs.appendChild(lg);
|
|
spec.options.forEach(function (pair) {
|
|
var lab = el("label", "choice");
|
|
var r = el("input");
|
|
r.type = "radio";
|
|
r.name = spec.id;
|
|
r.value = pair[0];
|
|
r.id = spec.id + "-" + pair[0];
|
|
lab.appendChild(r);
|
|
lab.appendChild(el("span", "", pair[1]));
|
|
fs.appendChild(lab);
|
|
});
|
|
var er = el("p", "err", "");
|
|
er.hidden = true;
|
|
fs.appendChild(er);
|
|
return fs;
|
|
}
|
|
var lb = el("label", "", spec.label);
|
|
lb.setAttribute("for", "fb-" + spec.id);
|
|
var ctl;
|
|
if (spec.type === "select") {
|
|
ctl = el("select");
|
|
ctl.appendChild(new Option("— choose —", ""));
|
|
spec.options.forEach(function (pair) { ctl.appendChild(new Option(pair[1], pair[0])); });
|
|
} else if (spec.type === "textarea") {
|
|
ctl = el("textarea");
|
|
ctl.rows = 4;
|
|
} else {
|
|
ctl = el("input");
|
|
ctl.type = "text";
|
|
}
|
|
ctl.id = "fb-" + spec.id;
|
|
ctl.name = spec.id;
|
|
f.appendChild(lb);
|
|
f.appendChild(ctl);
|
|
if (spec.hint) f.appendChild(el("p", "hint", spec.hint));
|
|
var e = el("p", "err", "");
|
|
e.hidden = true;
|
|
f.appendChild(e);
|
|
return f;
|
|
}
|
|
|
|
function feedbackPanel() {
|
|
var box = el("div", "panel");
|
|
box.appendChild(el("h2", "", "How did it go?"));
|
|
box.appendChild(el("p", "detail", "Answer in your own words. Your answers come to us — nothing here is published."));
|
|
var form = el("form");
|
|
form.setAttribute("novalidate", "novalidate");
|
|
|
|
FIELDS.forEach(function (spec) { form.appendChild(fieldBlock(spec)); });
|
|
|
|
var line = status("", "");
|
|
var btn = el("button", "btn", "Send feedback");
|
|
btn.type = "submit";
|
|
form.appendChild(btn);
|
|
form.appendChild(line);
|
|
|
|
form.addEventListener("submit", function (ev) {
|
|
ev.preventDefault();
|
|
var bad = false;
|
|
FIELDS.forEach(function (spec) {
|
|
var holder = form.querySelector('[data-field="' + spec.id + '"]');
|
|
var err = holder.querySelector(".err");
|
|
var v = "";
|
|
if (spec.type === "radio") {
|
|
var checked = form.querySelector('input[name="' + spec.id + '"]:checked');
|
|
v = checked ? checked.value : "";
|
|
} else {
|
|
var ctl = form.querySelector("#fb-" + spec.id);
|
|
v = ctl ? ctl.value.trim() : "";
|
|
}
|
|
if (spec.required && !v) {
|
|
holder.setAttribute("data-bad", "1");
|
|
err.textContent = "Please answer this before sending.";
|
|
err.hidden = false;
|
|
bad = true;
|
|
} else {
|
|
holder.removeAttribute("data-bad");
|
|
err.hidden = true;
|
|
}
|
|
});
|
|
if (bad) {
|
|
line.className = "status state-warn";
|
|
line.textContent = "Some answers are missing — see the notes above.";
|
|
var firstBad = form.querySelector('[data-bad="1"] input, [data-bad="1"] textarea, [data-bad="1"] select');
|
|
if (firstBad) firstBad.focus();
|
|
return;
|
|
}
|
|
|
|
// Build the body. The answers and nothing else — no name, no email, no identifier.
|
|
var body = { form: "feedback" };
|
|
FIELDS.forEach(function (spec) {
|
|
if (spec.type === "radio") {
|
|
var checked = form.querySelector('input[name="' + spec.id + '"]:checked');
|
|
body[spec.id] = checked ? checked.value : "";
|
|
} else {
|
|
var ctl = form.querySelector("#fb-" + spec.id);
|
|
body[spec.id] = ctl ? ctl.value.trim() : "";
|
|
}
|
|
});
|
|
|
|
btn.disabled = true;
|
|
line.className = "status";
|
|
line.textContent = "Sending…";
|
|
fetchJson(C.submitUrl, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body)
|
|
}).then(function (res) {
|
|
if (!res.ok) {
|
|
btn.disabled = false;
|
|
line.className = "status state-warn";
|
|
line.textContent = "We could not send your feedback — the service answered " + res.status +
|
|
(msgOf(res.body) ? " — " + msgOf(res.body) : "") + ". Your answers are still here; try again.";
|
|
return;
|
|
}
|
|
line.className = "status state-ok";
|
|
line.textContent = "Thank you — your feedback reached us.";
|
|
btn.disabled = true;
|
|
form.querySelectorAll("input, textarea, select, button").forEach(function (n) {
|
|
if (n !== btn) n.disabled = true;
|
|
});
|
|
}).catch(function () {
|
|
btn.disabled = false;
|
|
line.className = "status state-warn";
|
|
line.textContent = "We could not reach the service. Your answers are still here; try again.";
|
|
});
|
|
});
|
|
|
|
box.appendChild(form);
|
|
return box;
|
|
}
|
|
|
|
// ---- Render ---------------------------------------------------------------------------
|
|
// One state, always: the form. Nothing is read on load, so there is no fetch here.
|
|
show([progressBar(1), signupPanel(), feedbackPanel()]);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|