From 945b102d1a1380c0ee0baa8cf1de1ead4ddf56b3 Mon Sep 17 00:00:00 2001 From: TEJAS <98630752+tejaskh3@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:40:01 +0530 Subject: [PATCH] Dev to Main Sync (#949) * Subscription feature (#936) * feat: add form to collect subscription data * feat: add form to collect subscription data * WIP: add ember-phone-input * feat: add not loggedin and subscribed screen and integreate API * feat: fixing bug * fix: bug to show form even if user is already subscribed * fix: urls * fix: urls * fix: urls * delete: service subscribe test * fix: resolve comments * Update app/components/header.hbs Co-authored-by: Mehul Kiran Chaudhari <55375534+MehulKChaudhari@users.noreply.github.com> * fix: comments and remove modal * fix: phone number input * fix: content change * fix: remove card * fix: remove comments * fix:subscribe message --------- Co-authored-by: Vinit khandal <111434418+vinit717@users.noreply.github.com> Co-authored-by: Mehul Kiran Chaudhari <55375534+MehulKChaudhari@users.noreply.github.com> * subscription feature fixes (#944) * fix: navbar & css & phone validation * fix: PR comments * feat: add error to in valid input * fix: lint --------- Co-authored-by: Vinit khandal <111434418+vinit717@users.noreply.github.com> Co-authored-by: Mehul Kiran Chaudhari <55375534+MehulKChaudhari@users.noreply.github.com> --- app/components/header.hbs | 2 +- app/components/join-section.hbs | 3 + app/constants/regex.js | 2 + app/constants/urls.js | 1 + app/controllers/subscribe.js | 100 ++++++++++++ app/models/user.js | 3 + app/router.js | 1 + app/routes/subscribe.js | 3 + app/styles/app.css | 2 + app/styles/base-modal.module.css | 6 +- app/styles/join-section.module.css | 27 ++++ app/styles/phone-input.module.css | 23 +++ app/styles/subscribe.module.css | 242 +++++++++++++++++++++++++++++ app/templates/subscribe.hbs | 49 ++++++ config/environment.js | 6 + package.json | 1 + yarn.lock | 24 +++ 17 files changed, 493 insertions(+), 2 deletions(-) create mode 100644 app/constants/regex.js create mode 100644 app/controllers/subscribe.js create mode 100644 app/routes/subscribe.js create mode 100644 app/styles/phone-input.module.css create mode 100644 app/styles/subscribe.module.css create mode 100644 app/templates/subscribe.hbs diff --git a/app/components/header.hbs b/app/components/header.hbs index dfd80d93..54224285 100644 --- a/app/components/header.hbs +++ b/app/components/header.hbs @@ -51,7 +51,7 @@ class="nav__element" href={{this.STATUS_URL}} >Status - {{#if @dev}} + {{#if @dev}}
  • {{! TODO - remove query for dev when it goes to production }} + {{else}}
    diff --git a/app/constants/regex.js b/app/constants/regex.js new file mode 100644 index 00000000..59c5b265 --- /dev/null +++ b/app/constants/regex.js @@ -0,0 +1,2 @@ +export const phoneNumberRegex = + /^[+]{1}(?:[0-9\-\\(\\)\\/.]\s?){6,15}[0-9]{1}$/; diff --git a/app/constants/urls.js b/app/constants/urls.js index b65938f2..e4eaf6e0 100644 --- a/app/constants/urls.js +++ b/app/constants/urls.js @@ -99,3 +99,4 @@ export const SOCIALS = { }; export const ANKUSH_TWITTER = 'https://twitter.com/ankushdharkar'; +export const RDS_TWITTER = 'https://x.com/realdevsquad'; diff --git a/app/controllers/subscribe.js b/app/controllers/subscribe.js new file mode 100644 index 00000000..278adef8 --- /dev/null +++ b/app/controllers/subscribe.js @@ -0,0 +1,100 @@ +import Controller from '@ember/controller'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import { RDS_TWITTER, APPS } from '../constants/urls'; +import { TOAST_OPTIONS } from '../constants/toast-options'; +import { phoneNumberRegex } from '../constants/regex'; + +export default class SubscribeController extends Controller { + @service login; + @tracked isFormOpen = false; + @tracked email = ''; + @tracked phone = ''; + @tracked userData = null; + @tracked isLoading = false; + @tracked showSubscribedMessage = false; + @service toast; + @tracked isPhoneValid = true; + + RDS_TWITTER = RDS_TWITTER; + + constructor() { + super(...arguments); + this.userData = this.login.userData; + } + + get isLoggedIn() { + return this.login.isLoggedIn; + } + + get isSubscribed() { + return this.login.userData.isSubscribed; + } + + get isSubmitDisabled() { + const isPhoneValid = !this.phone || phoneNumberRegex.test(this.phone); + return !this.email || !isPhoneValid; + } + + @action + toggleFormModal() { + this.isFormOpen = !this.isFormOpen; + } + + @action + updateEmail(event) { + this.email = event.target.value; + } + + @action + updatePhone(event) { + this.phone = event.target.value; + this.isPhoneValid = !this.phone || phoneNumberRegex.test(this.phone); + } + + @action + async handleSubmit(event) { + event.preventDefault(); + if (!this.isSubmitDisabled) { + this.isLoading = true; + try { + const url = `${APPS.API_BACKEND}/subscription?dev=true`; + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify({ + email: this.email, + phoneNumber: this.phone, + }), + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }); + if (!response.ok) { + this.toast.error( + 'Something went wrong. Please try again.', + '', + TOAST_OPTIONS, + ); + } else { + this.login.userData.isSubscribed = true; + this.isFormOpen = false; + this.showSubscribedMessage = true; + this.toast.success('🎉 Thankyou for subscribing!', '', TOAST_OPTIONS); + } + } catch (error) { + console.log(error); + this.toast.error( + `Something went wrong. ${error.message}`, + '', + TOAST_OPTIONS, + ); + } finally { + this.isLoading = false; + } + this.email = ''; + this.phone = ''; + } + } +} diff --git a/app/models/user.js b/app/models/user.js index dbd0f80d..1a1caebb 100644 --- a/app/models/user.js +++ b/app/models/user.js @@ -20,4 +20,7 @@ export default class UserModel extends Model { @attr profileURL; @attr profileStatus; @attr website; + @attr isSubscribed; + @attr phoneNumber; + @attr email; } diff --git a/app/router.js b/app/router.js index 111652e7..a78344ed 100644 --- a/app/router.js +++ b/app/router.js @@ -15,4 +15,5 @@ Router.map(function () { this.route('goto'); this.route('events'); this.route('debug'); + this.route('subscribe'); }); diff --git a/app/routes/subscribe.js b/app/routes/subscribe.js new file mode 100644 index 00000000..b2338e80 --- /dev/null +++ b/app/routes/subscribe.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class SubscribeRoute extends Route {} diff --git a/app/styles/app.css b/app/styles/app.css index 9de6edd7..48c90b21 100644 --- a/app/styles/app.css +++ b/app/styles/app.css @@ -41,6 +41,8 @@ @import url("tooltip.module.css"); @import url("debug.module.css"); @import url("unauthenticated.module.css"); +@import url("subscribe.module.css"); +@import url("phone-input.module.css"); * { margin: 0; diff --git a/app/styles/base-modal.module.css b/app/styles/base-modal.module.css index 74c0e666..f44310f4 100644 --- a/app/styles/base-modal.module.css +++ b/app/styles/base-modal.module.css @@ -9,7 +9,11 @@ } .base-modal--show { - display: block; + display: flex; + align-items: center; + justify-content: center; + background-color: #000000b2; + backdrop-filter: blur(5px); } .base-modal--hide { diff --git a/app/styles/join-section.module.css b/app/styles/join-section.module.css index a63cda06..203185e5 100644 --- a/app/styles/join-section.module.css +++ b/app/styles/join-section.module.css @@ -41,6 +41,13 @@ line-height: 175%; } +.links__container { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} + .join__link { display: inline-block; margin-top: 2rem; @@ -54,11 +61,23 @@ padding: 1.25rem 3rem; } +.subscribe__link { + display: flex; + justify-content: center; + align-items: center; + gap: 5px; + padding: 1.125rem 3.75rem; +} + .join__link:hover { background-color: var(--color-pink); transition-duration: 250ms; } +.subscribe__link span { + font-size: 1.125rem; +} + .join__link--new { background-color: var(--color-button-disabled); cursor: not-allowed; @@ -126,6 +145,10 @@ font-size: 1.25rem; padding: 1rem 2.5rem; } + + .subscribe__link span { + font-size: 0.75rem; + } } @media (width <=425px) { @@ -147,4 +170,8 @@ font-size: 1rem; padding: 0.75rem 2rem; } + + .subscribe__link span { + font-size: 0.75rem; + } } diff --git a/app/styles/phone-input.module.css b/app/styles/phone-input.module.css new file mode 100644 index 00000000..1ead37c9 --- /dev/null +++ b/app/styles/phone-input.module.css @@ -0,0 +1,23 @@ +.phone-input { + display: flex; + align-items: center; + margin-bottom: 10px; +} + +.country-code-select { + margin-right: 10px; +} + +.phone-number-input { + flex-grow: 1; +} + +.phone-input select, +.phone-input input[type="tel"] { + width: 100%; + padding: 5px; +} + +button { + padding: 5px 10px; +} diff --git a/app/styles/subscribe.module.css b/app/styles/subscribe.module.css new file mode 100644 index 00000000..b610d4d8 --- /dev/null +++ b/app/styles/subscribe.module.css @@ -0,0 +1,242 @@ +@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"); + +.subscribe__container { + background-color: var(--color-white); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2rem; + text-align: center; + min-height: 76vh; +} + +.subscribe__container h1, +.subscribe__form_container h1 { + font-size: 2rem; + font-weight: 700; + color: #111827; + text-align: center; +} + +.subscribe__container p, +.subscribe__form_container p { + font-family: Inter, sans-serif; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.875rem; + text-align: center; +} + +.notification__text { + font-size: 18px; + color: #dc2626; +} + +.sub__text { + font-size: 16px; + color: #374151; +} + +.notify__btn { + font-size: 16px; + background-color: #1e429f; + color: white; + padding: 0.75rem 1.5rem; + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s ease; + text-align: center; +} + +.notify__btn:hover { + background-color: #1558b0; +} + +.notify__btn a { + display: block; + padding: 12px; + background-color: #1e429f; + color: white; + text-decoration: none; + border-radius: 6px; + font-weight: 600; + transition: background-color 0.3s; +} + +.subscribed__confirmed nav a { + display: block; + padding: 12px; + background-color: #1e429f; + color: white; + text-decoration: none; + border-radius: 6px; + font-weight: 600; + transition: background-color 0.3s; +} + +.notify__btn a:hover, +.notify__btn:hover a { + background-color: #163a7b; +} + +.subscribe__form_container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 5px; +} + +.subscribe__form_container p { + font-family: Inter, sans-serif; + font-size: 20px; + font-weight: 400; + line-height: 30px; + color: #6b7280; +} + +.subscribe__form { + background-color: white; + width: 100%; + max-width: 500px; + position: relative; + box-sizing: border-box; + padding: 30px; + box-shadow: rgb(17 12 46 / 15%) 0 48px 100px 0; + border-radius: 8px; + margin-top: 5rem; +} + +.subscribed__confirmed__close__btn { + position: absolute; + top: 12px; + right: 15px; + padding: 5px; + background: none; + border: none; + cursor: pointer; + font-size: 24px; + line-height: 1; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: background-color 0.3s ease; +} + +.input__group { + margin-bottom: 1.5rem; + display: flex; + flex-direction: column; +} + +.input__group label { + font-family: Inter, sans-serif; + font-size: 16px; + font-weight: 500; + line-height: 24px; + text-align: left; +} + +.input__group__span { + color: #374151; +} + +.input__group input::placeholder { + color: #6b7280; +} + +.input__group input { + padding: 0.75rem; + border: 1px solid #d1d5db; + border-radius: 6px; + font-family: Inter, sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 17.5px; + text-align: left; + color: #000; +} + +.invalid-input { + border-color: #dc2626; + color: red; +} + +.submit__btn { + padding: 1rem; + background-color: #1e429f; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.subscribe__button { + width: 100%; +} + +.subscribe__button:disabled { + background-color: #dadada; +} + +.login__message { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2rem; + text-align: center; +} + +.login__message h1 { + font-size: 32px; + font-weight: 700; + color: #111827; +} + +.login__message p { + font-family: Inter, sans-serif; + font-size: 20px; + font-weight: 400; + line-height: 30px; + color: #6b7280; +} + +.login__message .sub__text { + font-size: 16px; + color: #374151; + margin-top: 1rem; +} + +.already-subscribed { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1.5rem; + text-align: center; + max-width: 600px; + margin: 0 auto; +} + +.already-subscribed h1 { + font-size: 32px; + font-weight: 700; + color: #1e429f; + text-align: center; +} + +.already-subscribed p { + font-family: Inter, sans-serif; + font-size: 18px; + font-weight: 400; + line-height: 28px; + color: #374151; + text-align: center; +} diff --git a/app/templates/subscribe.hbs b/app/templates/subscribe.hbs new file mode 100644 index 00000000..1eb4eda5 --- /dev/null +++ b/app/templates/subscribe.hbs @@ -0,0 +1,49 @@ +{{page-title 'Subscribe'}} + + diff --git a/config/environment.js b/config/environment.js index f0094847..18dc1fe2 100644 --- a/config/environment.js +++ b/config/environment.js @@ -21,14 +21,20 @@ module.exports = function (environment) { fastboot: { hostWhitelist: [/^localhost:\d+$/, 'dev.realdevsquad.com'], }, + phoneInput: { + lazyLoad: true, + hasPrepend: false, + }, }; if (environment === 'production') { ENV.fastboot.hostWhitelist = ['realdevsquad.com']; + ENV.phoneInput.hasPrepend = true; } if (environment === 'staging') { ENV.fastboot.hostWhitelist = ['beta.realdevsquad.com']; + ENV.phoneInput.hasPrepend = true; } if (environment === 'development') { diff --git a/package.json b/package.json index 88b71842..87edafbc 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "d3-cloud": "1.2.7", "dotenv": "16.0.2", "ember-d3": "0.5.1", + "ember-phone-input": "^10.0.0", "exists-sync": "0.1.0", "fastboot-app-server": "3.3.2" }, diff --git a/yarn.lock b/yarn.lock index a0e258c2..5ee44be1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3110,6 +3110,15 @@ ember-cli-babel "^7.26.11" ember-modifier-manager-polyfill "^1.2.0" +"@ember/render-modifiers@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@ember/render-modifiers/-/render-modifiers-2.1.0.tgz#f4fff95a8b5cfbe947ec46644732d511711c5bf9" + integrity sha512-LruhfoDv2itpk0fA0IC76Sxjcnq/7BC6txpQo40hOko8Dn6OxwQfxkPIbZGV0Cz7df+iX+VJrcYzNIvlc3w2EQ== + dependencies: + "@embroider/macros" "^1.0.0" + ember-cli-babel "^7.26.11" + ember-modifier-manager-polyfill "^1.2.0" + "@ember/string@3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@ember/string/-/string-3.1.1.tgz#0a5ac0d1e4925259e41d5c8d55ef616117d47ff0" @@ -9188,6 +9197,16 @@ ember-page-title@8.2.3: "@embroider/addon-shim" "^1.8.7" "@simple-dom/document" "^1.4.0" +ember-phone-input@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/ember-phone-input/-/ember-phone-input-10.0.0.tgz#0aaac5e57e3cbd3f20973138d39c77caf5c6b36b" + integrity sha512-kebV05W7Y2+DN+xSwvPWe0ocVI3gK2UlaOjw8G1g5rw1Aoe0ouFI5ecCs+/5YvHRzPZzpASyrC3w63vpgSo9jA== + dependencies: + "@ember/render-modifiers" "^2.1.0" + "@embroider/addon-shim" "^1.8.7" + intl-tel-input "^18.0.0" + rsvp "^4.8.5" + ember-qunit@8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-8.0.2.tgz#a6346136cba785853f176dfa6ed25e3f0a11b7a0" @@ -11376,6 +11395,11 @@ intersection-observer-admin@~0.3.2: resolved "https://registry.yarnpkg.com/intersection-observer-admin/-/intersection-observer-admin-0.3.3.tgz#176a2a08c1cfa9ec3bc74d81cb9ba6483c30e625" integrity sha512-aKMJPw/8cxybcgYTbnwGn87VgSFbSNNqeChRJahD+ai+jtwlCOdIcEvtuBd2BWO9bPuylVgeQVmGGfX2aS1NIg== +intl-tel-input@^18.0.0: + version "18.5.3" + resolved "https://registry.yarnpkg.com/intl-tel-input/-/intl-tel-input-18.5.3.tgz#20b18431cb802d33c118f52e332e218e641ec09b" + integrity sha512-ncFqSpkdGf2YC/FvAiwBH44KAeRG8L7aqDODEpOvMAT3ZpBtvc/WtwaQ/6X4+HKDTlGkobdBjr6P3nAMwO8jtA== + invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"