summaryrefslogtreecommitdiff
path: root/http/src/contact.upphtml
blob: 2d605a38f3f4ed6062656111fb2a55ab131098df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!
export TITLE="Contact"
export DESCRIPTION="Contact Joe Carstairs"
pp "${SHARE}"/components/meta.upphtml
#!

#!
pp "${SHARE}"/components/otp-dialog.upphtml
#!

<main>
<form class=contact-form>
  <h1>Contact me</h1>
  <p hidden class=error></p>
  <label for=name>Name</label>
  <input id=name name=name type=text required>
  <label for=email>Email</label>
  <input id=email name=email type=email required>
  <label for=message>Message</label>
  <textarea id=message name=message required></textarea>
  <input type=submit value=Send>
</form>

<section class=success hidden=true>
  <h1>You sent me a message!</h1>
  <p>Thanks for that. I may be in touch.</p>
  <p>In case you forgot, your message was this:</p>
  <hr>
  <dl>
    <dt>Name</dt> <dd class=sentname>???</dd>
    <dt>Email</dt> <dd class=sentemail>???</dd>
    <dt>Message</dt> <dd class=sentmessage>???</dd>
  </dl>
</section>

<script type=module>
  import { resendOtp } from '/scripts/contact/resend-otp.js';
  import { submitContactForm } from '/scripts/contact/submit-contact-form.js';
  import { submitOtpForm } from '/scripts/contact/submit-otp-form.js';

  function locateOrPanic(selector, desc, root) {
    const elem = (root ?? document).querySelector(selector);
    if (!elem) {
      alert('Technical error: could not locate ' + desc + '. Please let Joe know if you have another means of contacting him.');
      throw new Error('Could not locate ' + desc);
    }
    return elem;
  }

  const contactForm = locateOrPanic('form.contact-form', 'contact form');
  const otpDialog = locateOrPanic('dialog.otp-dialog', 'OTP dialog');
  const otpForm = locateOrPanic('form.otp-form', 'OTP form');
  const successSection = document.querySelector('section.success');
  let resendButtonInterval = undefined;

  const selectors = {
    contactForm: {
      emailElem: () => locateOrPanic('input[name=email]', 'email input', contactForm),
      errorElem: () => contactForm.querySelector('.error'),
      nameElem: () => locateOrPanic('input[name=name]', 'name input', contactForm),
      messageElem: () => locateOrPanic('textarea[name=message]', 'message textarea', contactForm),
      self: () => contactForm,
      submitButton: () => contactForm.querySelector('input[type=submit]'),
    },
    otpDialog: {
      allOtpInputs: () => otpForm.querySelectorAll('input:not([type=submit])'),
      errorElem: () => otpDialog.querySelector('.error'),
      firstOtpInput: () => otpForm.querySelector('input:not([type=submit]):first-child'),
      otpForm: () => otpForm,
      otpRecipient: () => otpDialog.querySelector('.otp-recipient'),
      otpValidUntil: () => otpDialog.querySelector('.otp-valid-until'),
      resendButton: () => otpDialog.querySelector('button.resend-button'),
      self: () => otpDialog,
      submitButton: () => otpForm.querySelector('input[type=submit]'),
    },
    successSection: {
      email: () => successSection?.querySelector('.sentemail') ?? null,
      name: () => successSection?.querySelector('.sentname') ?? null,
      message: () => successSection?.querySelector('.sentmessage') ?? null,
      self: () => successSection,
    }
  };

  contactForm.addEventListener('submit', async (event) => {
    event.preventDefault();
    ({ resendButtonInterval } = await submitContactForm(selectors, resendButtonInterval));
  });

  selectors.otpDialog.resendButton()?.addEventListener('click', async () => {
    ({ resendButtonInterval } = await resendOtp(selectors, resendButtonInterval));
  });

  otpForm.addEventListener('submit', async (event) => {
    event.preventDefault();
    await submitOtpForm(selectors);
  });
</script>
</main>