From e385e2eb90976ca06ec98a248c840029516a7d68 Mon Sep 17 00:00:00 2001 From: Aleksandar Petkov Date: Tue, 19 Dec 2023 09:48:30 +0200 Subject: [PATCH 01/13] pdf/Certificate: Get donor's names from session token (#1690) Anonymous donations don't have personId to find them by users --- src/components/client/pdf/Certificate.tsx | 13 +++++++------ src/pages/api/pdf/certificate/[donationId].tsx | 2 +- src/service/auth.ts | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/client/pdf/Certificate.tsx b/src/components/client/pdf/Certificate.tsx index 9106bf988..ea126bee7 100644 --- a/src/components/client/pdf/Certificate.tsx +++ b/src/components/client/pdf/Certificate.tsx @@ -6,6 +6,7 @@ import { formatDateString } from 'common/util/date' import { money } from 'common/util/money' import theme from 'common/theme' import { DonationType } from 'gql/donations.enums' +import { ServerUser } from 'service/auth' Font.register({ family: 'Arial', @@ -122,11 +123,12 @@ const styles = StyleSheet.create({ type Props = { donation: DonationResponse + user: ServerUser | null | undefined } -export default function Certificate({ donation }: Props) { - const companyName = donation.person?.company - ? donation.person.company.companyName - : donation.affiliate.company.companyName +export default function Certificate({ donation, user }: Props) { + const userName = `${user?.given_name} ${user?.family_name}` ?? '' + const companyName = `${user?.company}` ?? '' + return ( @@ -143,8 +145,7 @@ export default function Certificate({ donation }: Props) { С този сертификат Управителният съвет на Сдружение „Подкрепи БГ“ удостоверява, че: - {donation.type === DonationType.donation && - `${donation.person?.firstName} ${donation.person?.lastName}`} + {donation.type === DonationType.donation && userName} {donation.type === DonationType.corporate && companyName} diff --git a/src/pages/api/pdf/certificate/[donationId].tsx b/src/pages/api/pdf/certificate/[donationId].tsx index 7a73b6f6b..4fa29fa90 100644 --- a/src/pages/api/pdf/certificate/[donationId].tsx +++ b/src/pages/api/pdf/certificate/[donationId].tsx @@ -24,7 +24,7 @@ const Handler: NextApiHandler = async (req: NextApiRequest, res: NextApiResponse if (!donation) { res.status(404).json({ notFound: true }) } else { - const pdfStream = await renderToStream() + const pdfStream = await renderToStream() res.setHeader('Content-Type', 'application/pdf') pdfStream.pipe(res) } diff --git a/src/service/auth.ts b/src/service/auth.ts index bf38d8c0b..88135d086 100644 --- a/src/service/auth.ts +++ b/src/service/auth.ts @@ -51,6 +51,7 @@ export type ServerUser = ParsedToken & { session_state: string 'allowed-origins': string[] selfReg?: boolean + company: string // access realm_access: { roles: RealmRole[] } resource_access: { account: { roles: ResourceRole[] } } From 3762cde4d46ea0690f8bd801a3e7214f74ec33c0 Mon Sep 17 00:00:00 2001 From: Ani Date: Wed, 3 Jan 2024 18:56:10 +0200 Subject: [PATCH 02/13] Update year in the footer (#1695) Co-authored-by: Ani Kalpachka --- public/locales/bg/common.json | 2 +- public/locales/en/common.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 52b83c3e7..33e3190ae 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -77,7 +77,7 @@ "faq": "Често задавани въпроси", "privacy-policy": "Защита на лични данни", "terms-of-service": "Общи условия", - "copyrights": "Podkrepi.bg ©2023 Всички права запазени.", + "copyrights": "Podkrepi.bg ©2024 Всички права запазени.", "hosting-partner": "Хостинг партньор:", "social": { "facebook": "Facebook", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 1cc29d1ea..652068566 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -75,7 +75,7 @@ "faq": "Frequently asked questions", "privacy-policy": "Privacy Policy", "terms-of-service": "Terms of Service", - "copyrights": "Podkrepi.bg ©2023 All rights reserved.", + "copyrights": "Podkrepi.bg ©2024 All rights reserved.", "hosting-partner": "Hosting partner:", "partners": "Partners", "social": { From 454a978eb514d4d40f5a3eddee14249c8033208a Mon Sep 17 00:00:00 2001 From: Ani Date: Wed, 3 Jan 2024 20:18:23 +0200 Subject: [PATCH 03/13] Update translation (#1692) * Update translation * Fix build errors --------- Co-authored-by: Ani Kalpachka --- public/locales/bg/campaigns.json | 5 ++--- public/locales/bg/news.json | 2 +- public/locales/en/campaigns.json | 3 +-- src/components/client/campaigns/InlineDonation.tsx | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/public/locales/bg/campaigns.json b/public/locales/bg/campaigns.json index 25521718e..0d45ab1da 100644 --- a/public/locales/bg/campaigns.json +++ b/public/locales/bg/campaigns.json @@ -194,8 +194,7 @@ "date": "Дата:", "news": "Новини", "wishes": "Пожелания", - "nowishes": "Няма добавени пожелания", - "seeAll": "Виж всички" + "nowishes": "Няма добавени пожелания" }, "info-graphics": { "donation-title": "100% от дарението отива при нуждаещите се", @@ -254,4 +253,4 @@ "art": "Изкуство", "others": "Други" } -} +} \ No newline at end of file diff --git a/public/locales/bg/news.json b/public/locales/bg/news.json index 16b429412..9c101b5aa 100644 --- a/public/locales/bg/news.json +++ b/public/locales/bg/news.json @@ -4,7 +4,7 @@ "edit-form-heading": "Редактирайте статия", "read-more": "Прочети повече", "read-less": "Прочети по-малко", - "see-all-news": "Виж всички новини", + "see-all-news": "Вижте всички новини", "news-not-found": "Не бяха намерени новини за тази кампания", "write-new-article": "Напишете нова статия", "status": { diff --git a/public/locales/en/campaigns.json b/public/locales/en/campaigns.json index 8609116b4..ae5a7165a 100644 --- a/public/locales/en/campaigns.json +++ b/public/locales/en/campaigns.json @@ -180,8 +180,7 @@ "date": "Date:", "news": "News", "wishes": "Wishes", - "nowishes": "No wishes yet", - "seeAll": "Show all" + "nowishes": "No wishes yet" }, "info-graphics": { "donation-title": "100% of the donation goes to those in need", diff --git a/src/components/client/campaigns/InlineDonation.tsx b/src/components/client/campaigns/InlineDonation.tsx index cd58f931f..6374c62ab 100644 --- a/src/components/client/campaigns/InlineDonation.tsx +++ b/src/components/client/campaigns/InlineDonation.tsx @@ -335,7 +335,7 @@ export default function InlineDonation({ campaign }: Props) { {wishList && } {wishList?.totalCount !== 0 && ( } onDelete={() => { return From e6166b1db8a8deb9072d1bb2733e4db50d30b55e Mon Sep 17 00:00:00 2001 From: Aleksandar Petkov Date: Wed, 3 Jan 2024 22:08:24 +0200 Subject: [PATCH 04/13] campaign-news: Remove sourceLink field (#1696) Not currently used, and causes confusion --- src/components/client/campaign-news/secured/CreateForm.tsx | 4 ++-- src/components/client/campaign-news/secured/EditForm.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/client/campaign-news/secured/CreateForm.tsx b/src/components/client/campaign-news/secured/CreateForm.tsx index 13290a3f6..58ca10d8e 100644 --- a/src/components/client/campaign-news/secured/CreateForm.tsx +++ b/src/components/client/campaign-news/secured/CreateForm.tsx @@ -206,7 +206,7 @@ export default function CreateForm({ campaignId = '', isAdmin = true }: Campaign }} /> - + {/* - + */} {isAdmin && } diff --git a/src/components/client/campaign-news/secured/EditForm.tsx b/src/components/client/campaign-news/secured/EditForm.tsx index d7f948910..bed31df12 100644 --- a/src/components/client/campaign-news/secured/EditForm.tsx +++ b/src/components/client/campaign-news/secured/EditForm.tsx @@ -237,7 +237,7 @@ export default function EditForm({ article, campaignId = '', isAdmin = true }: P }} /> - + {/* - + */} {isAdmin && } From f37755e5e5835141e936c1a37134bbbf76aa3660 Mon Sep 17 00:00:00 2001 From: RalitsaIlieva Date: Wed, 3 Jan 2024 21:11:05 +0100 Subject: [PATCH 05/13] New design notifications news (#1673) * New design for campaign news subscription * format change * lint fix * news notifications added * buttons for notification commented * Uncommented buttons for notifications * lint fix * small fixes * [#1554] headings font size bug fixes (#1613) * headings font size bug fixes * removed library from package.json * Terms and GDPR added in the registerForm (#1617) * Terms and GDPR added in the registerForm * Format check added * Some error messages added in the RegisterForm * add RalitsaIlieva as a contributor for code (#1618) * update README.md [skip ci] * update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> * New font Commissioner (#1620) Co-authored-by: igoychev * Update BG text for Reports page (#1621) Co-authored-by: ani-kalpachka * Update team members (#1622) Co-authored-by: ani-kalpachka * fix: rounds correctly Donated money value in Statistics section (#1623) * build(deps): bump @babel/traverse from 7.22.8 to 7.23.2 (#1624) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.8 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Upgrade of translation libraries and related (#1616) * upgraded NextJS to fix dependabot vulnerability warnings * fixed linter and formatting * reverted next to 13.4.12, updated MUI and translation libraries * upgraded playwright to latest * fixed language change and corrected decimal separators * forced resolution for postcss and zod to fix security recommendations * added locale for tests to fix decimal separator mixups * donation amount changed to integer to avoid language specific decimal separators * upgraded node to v20 * fixing the docker build context to use the already checked out code from github checkout action * Update mobile Guarantors slider (#1629) * Update Guarantors slider * Revert unnecessary changes --------- Co-authored-by: ani-kalpachka * Update alignment of Bank details on Donation (mobile) (#1628) * Update bank details on donation * Update reasoning --------- Co-authored-by: ani-kalpachka * build(deps): bump crypto-js from 4.1.1 to 4.2.0 (#1630) Bumps [crypto-js](https://github.com/brix/crypto-js) from 4.1.1 to 4.2.0. - [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0) --- updated-dependencies: - dependency-name: crypto-js dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Upgrade next version to 13.5.4 (#1631) * Update next version to 13.5.4 * i18n: Fix translations not working for dynamic paths * i18next.config: Detect user's locale from NEXT_LOCALE cookie * added cookies consent banner (#1634) * Update completed campaigns carousel (#1639) Co-authored-by: ani-kalpachka * [Stripe] Add refund functionality (#1635) * Add refund button * Add refundStore * Fix prettier problem * Remove log * Fix typos * refundClickClickHandler -> refundClickHandler * Show extPaymentId in confirmation box * Fix button typo * Show wishes on the top of campaign page (#1633) * fix: shows tabs for donors and wishes * fix: wishes tab shows messages and pagination * fix: adds btn 'Show all' to wishes tab, align wishes array * fix: InfoIcon align * fix: shuffle wishes array * fix: clear unused classes * Add Finance report for 2022 (#1642) Co-authored-by: ani-kalpachka * add kzhecheva as a contributor for code (#1643) * update README.md [skip ci] * update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> * format change * lint fix * news notifications added * buttons for notification commented * Uncommented buttons for notifications * Update Cookie consent popup (#1645) * Update cookie consent popup * removed auto accept on scroll --------- Co-authored-by: ani-kalpachka * Add check to refund stripe donations only (#1648) * Add if check to refund only stripe donations * Use enum for variables * Fix prettier * Adds tests for Wishes and Donors sections on the top of Campaign page (#1646) * feat: adds campaign summary section tests * upgrade_sentry_to_7.80 (#1654) * github actions update (#1655) * added dependabot to update github actions * added run-name for Release github workflow to better distinguish it in the actions list * build(deps): bump actions/setup-node from 3 to 4 (#1656) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/checkout from 3 to 4 (#1657) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump axios from 0.21.4 to 1.6.0 (#1661) Bumps [axios](https://github.com/axios/axios) from 0.21.4 to 1.6.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.21.4...v1.6.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump imranismail/setup-kustomize from 1 to 2 (#1660) Bumps [imranismail/setup-kustomize](https://github.com/imranismail/setup-kustomize) from 1 to 2. - [Release notes](https://github.com/imranismail/setup-kustomize/releases) - [Commits](https://github.com/imranismail/setup-kustomize/compare/v1.0.0...v2) --- updated-dependencies: - dependency-name: imranismail/setup-kustomize dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump docker/login-action from 2 to 3 (#1659) Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump docker/build-push-action from 3 to 5 (#1658) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * FIX: Added selfReg prop to the ServerUser obj an use it determinate if a user is form keycloak or external auth provider. (#1662) * add PetarDimitrov91 as a contributor for code (#1663) * update README.md [skip ci] * update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> * add kzhecheva as a contributor for code, and test (#1664) * update README.md [skip ci] * update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: igoychev * disabled button for manual import, added guard in rerun button (#1652) * disabled button for manual import,added guardin rerun button * added description comments * [1/2] Affiliate program Integration v1 (#1627) * services/apiEndpoints: Change endpoint for registration Endpoint for registration for individual users is now at /register/individual * campaigns: Include guaranteed donations in reachedAmount * donation.enums.ts: Add guaranteed DonationStatus Match with the values on the backend * donations: Use companyName when donation is made from corporate profile * auth/register: Change register request to match latest changes in backend * [SQUASH]: Donation improvements src/one-step-donation: Allow for corporate donations campaigns/InlineDonation: Limit the amount of donations on mobile to three campaigns/ViewCampaignPage: Push InlineDonation from top, to prevent conflict with the navigation bar on mobile campaigns/DonorsAndDonations: Handle different type of campaign donors * one-time-donation/Steps.tsx Add session to donate's dependency array Donate function needs to be redefined, with person's data in case user logs in on step two of donation flow. Without this change any information coming from acccount/me response is considered undefined, even if user logs in during the second step, as this information was not available during the definition of donate * one-time-donation/Steps.tsx: Add person to donation's dependency array In some cases person remains undefined, even though user is logged in * Allow corporate registrations * i18n: Add translations for new registration flow * Fix horizontal scroll on smaller viewport width * campaigns/DonationWishes.tsx: Show wishes from affiliate donations * pdf/Certificate.tsx: Use companyName if donation is made by corporate profile * pdf/Certificate: Move companyName condition out of the return statement Looks a bit cleaner that way * auth/profile: Changes for corporate profiles - Person's data is now prefetched to prevent any layout shifts and errors until person's data has been loaded. - Added new tab to summarize Affiliate's data which includes, as well as to cancel any guaranteed donations * auth/Register: Fix signin attempt on corporate registration -Sometimes the signin function is called before isSuccess state is switched to true. Use the response statusCode instead to check if the response is successfull -Fixed translations on RegisterSuccess * common/person: Allow for manual profile activation/deactivation - Added a new column profile type, to separate individual from corporate profiles * hooks/person: Fix cache not being invalidat on successfull active status response * pages/admin: Add section to manage Affiliate program * admin/affiliates: Remove unused import * profile/AffiliateProgramTab: Fix crash when donation is undefined In situations where affiliate record doesn't yet exist, donations is undefined, and it causes error * hooks/affiliate: Invalidate affiliate data when requesting to join affiliate program This way there is no need to restart the page * profile/affiliate: Add button to copy affiliate code utils/useCopyToClipbaord.ts: Change hook to copy text passed to copyUrl as parameter * AffiliateProgramTab: Summarize what is affiliate if user has not joined it -Copybutton is now hidden if no affiliateCode is present * CampaignDetails.tsx: Show campaign's summary data on page Includes available amount, guaranteed amount, sent amount, and added expenses * CampaignDetails.tsx: Remove unnnecessary Box component * bg/auth: Change text on successfull corporate registration Co-authored-by: Kalina Zhecheva * eslint: Resolve errors * fix: aligns campaignType translation (#1668) * added campaign donation chart (#1667) * build(deps): bump sharp from 0.30.7 to 0.32.6 (#1669) Bumps [sharp](https://github.com/lovell/sharp) from 0.30.7 to 0.32.6. - [Release notes](https://github.com/lovell/sharp/releases) - [Changelog](https://github.com/lovell/sharp/blob/main/docs/changelog.md) - [Commits](https://github.com/lovell/sharp/compare/v0.30.7...v0.32.6) --- updated-dependencies: - dependency-name: sharp dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Implement fullscreen image slider when image is clicked (#1676) Currently we don't have a gallery component, and when image is uploaded with role==gallery those images remain unusable on larger screens, due to their small size This commit makes it so a full-screen gallery like is opened whenever an image with role==gallery is clicked. * build(deps): bump next-auth from 4.22.1 to 4.24.5 (#1670) Bumps [next-auth](https://github.com/nextauthjs/next-auth) from 4.22.1 to 4.24.5. - [Release notes](https://github.com/nextauthjs/next-auth/releases) - [Commits](https://github.com/nextauthjs/next-auth/compare/next-auth@4.22.1...next-auth@4.24.5) --- updated-dependencies: - dependency-name: next-auth dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Remove legacy hotjar implementation (#1678) * Remove legacy hotjar implementation Hotjar is now loaded through the GTM * CampaignsPage.tsx: Remove Hotjar implementation * build(deps): bump @adobe/css-tools from 4.3.1 to 4.3.2 (#1679) Bumps [@adobe/css-tools](https://github.com/adobe/css-tools) from 4.3.1 to 4.3.2. - [Changelog](https://github.com/adobe/css-tools/blob/main/History.md) - [Commits](https://github.com/adobe/css-tools/commits) --- updated-dependencies: - dependency-name: "@adobe/css-tools" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update active team members (#1675) Co-authored-by: Ani Kalpachka * one-time-donation/LoginForm.tsx: Refetch useCurrentPerson when logged in (#1677) When user logs in trough donation step 2, person's data remains undefined due to data not being updated. Manually refetch the data coming from useCurrentPerson() after login to refresh the user's data * make the robots.txt file dynamic (#1680) * Add new active members (#1681) * lint fix * small fixes * uncommented code in Subscription Section * Unused variables deleted and self-closing tags fix * format changes * e is returned in SubscriptionPage * fix in expenses table and CheckboxField * rearrange in CampaignDetails * SubscribeModal removed from TeamSection * format fix * unused code deleted * removed Grid and SectionGridWrapper in TeamsMemberSection * format change --------- Signed-off-by: dependabot[bot] Co-authored-by: Dzhani Ivanov <68897146+dzhaniivanov@users.noreply.github.com> Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: igoychev Co-authored-by: Ani Co-authored-by: ani-kalpachka Co-authored-by: Kalina Zhecheva <60223025+kzhecheva@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: quantum-grit <91589884+quantum-grit@users.noreply.github.com> Co-authored-by: Aleksandar Petkov Co-authored-by: Nikolay Nachev <44066540+Nnachevvv@users.noreply.github.com> Co-authored-by: Petar Dimitrov <79804094+PetarDimitrov91@users.noreply.github.com> Co-authored-by: Anton Angelov <123360440+tongo-angelov@users.noreply.github.com> Co-authored-by: Ani Kalpachka Co-authored-by: yyosifov --- README.md | 2 + next.config.js | 4 +- public/locales/bg/auth.json | 2 + public/locales/bg/campaigns.json | 25 +- public/locales/bg/index.json | 4 + public/locales/bg/notifications.json | 6 +- public/locales/bg/profile.json | 1 - public/locales/bg/validation.json | 1 + public/locales/en/auth.json | 2 + public/locales/en/campaigns.json | 22 ++ public/locales/en/index.json | 4 + public/locales/en/notifications.json | 16 ++ public/locales/en/validation.json | 2 + .../auth/register/CorporateRegisterForm.tsx | 2 +- .../client/auth/register/RegisterForm.tsx | 2 +- .../client/campaigns/CampaignDetails.tsx | 49 +++- .../client/campaigns/InlineDonation.tsx | 33 +-- src/components/client/index/IndexPage.tsx | 2 + .../PlatformStatisticsSection.styled.tsx | 32 ++- .../PlatformStatisticsSection.tsx | 29 ++- .../SubscriptionSection.styled.tsx | 28 +++ .../SubscriptionSection.tsx | 62 +++++ .../TeamMembersSection/TeamMembersSection.tsx | 12 +- .../client/layout/Footer/Footer.styled.tsx | 9 + .../client/layout/Footer/LogoSocialIcons.tsx | 3 - .../client/layout/Footer/SocialIcons.tsx | 2 + .../client/layout/Footer/Subscription.tsx | 29 +++ .../notifications/CampaignSubscribeModal.tsx | 227 ++++++++++++------ .../notifications/GeneralSubscribeModal.tsx | 194 ++++++++++++--- .../client/notifications/SubscriptionPage.tsx | 48 ++-- .../one-time-donation/RegisterDialog.tsx | 2 +- .../common/form/AcceptNewsletterField.tsx | 25 +- src/components/common/form/CheckboxField.tsx | 13 +- src/pages/index.tsx | 8 +- 34 files changed, 703 insertions(+), 199 deletions(-) create mode 100644 public/locales/en/notifications.json create mode 100644 src/components/client/index/sections/SubscriptionSection/SubscriptionSection.styled.tsx create mode 100644 src/components/client/index/sections/SubscriptionSection/SubscriptionSection.tsx create mode 100644 src/components/client/layout/Footer/Subscription.tsx diff --git a/README.md b/README.md index 158dd3ea0..825cd8c9a 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,9 @@ Watch releases of this repository to be notified about future updates: ## Contributors ✨ + [![All Contributors](https://img.shields.io/badge/all_contributors-76-orange.svg?style=flat-square)](#contributors-) + Please check [contributors guide](https://github.com/podkrepi-bg/frontend/blob/master/CONTRIBUTING.md) for: diff --git a/next.config.js b/next.config.js index 963dfefc6..a968f4c27 100644 --- a/next.config.js +++ b/next.config.js @@ -53,8 +53,8 @@ const moduleExports = { }, { source: '/robots.txt', - destination: '/api/robots' - } + destination: '/api/robots', + }, ] }, async redirects() { diff --git a/public/locales/bg/auth.json b/public/locales/bg/auth.json index 77cf1f132..440e59019 100644 --- a/public/locales/bg/auth.json +++ b/public/locales/bg/auth.json @@ -12,6 +12,7 @@ }, "cta": { "login": "Вход", + "guest": "Като гост", "logout": "Изход", "register": "Регистрация", "send": "Изпрати", @@ -19,6 +20,7 @@ }, "fields": { "email": "Email", + "email-descriptive": "Въведи email адрес", "password": "Парола", "confirm-password": "Потвърждение на парола", "first-name": "Име", diff --git a/public/locales/bg/campaigns.json b/public/locales/bg/campaigns.json index 0d45ab1da..79c451fbc 100644 --- a/public/locales/bg/campaigns.json +++ b/public/locales/bg/campaigns.json @@ -73,7 +73,14 @@ "save": "Запази", "submit": "Изпрати", "apply": "Кандидатствайте", - "subscribe": "Абониране за известия", + "subscribe": "Абонирай се за email известия за кампанията", + "subscribeFooter": "Абонирай се за бюлетина", + "subscribeGeneral": "Абонирайте се за email известия от Подкрепи.бг", + "subscribe-monthly-newsletter": "Месечен бюлтеин на Подкрепи.бг", + "subscribeGeneralSubtext": "Получавайте нашия месечен бюлетин, в който ще Ви информираме за най-интересните новини от Подкрепи.бг!", + "subscribe-general-monthly-newsletter": "Получавайте нашия месечен бюлетин, за да сте в час най-интересните новини от Подкрепи.бг!", + "subscribeGeneralButton": "Абонирайте се за новини", + "subscribe-general-newsletter-button": "Абонирайте се", "support": "Дарете", "support-cause-today": "Подкрепете кауза днес!", "support-now": "Подкрепете сега", @@ -95,10 +102,18 @@ "allow-donation-on-complete": "Разрешете дарения след достигане на сумата" }, "subscribe": { - "confirm-sent": "Благодарим ви! На посочения e-mail адрес беше изпратено съобщение за потвърждение на вашето абониране.", - "confirm-subscribe": "Благодарим ви! Абонирахте се успешно.", - "subscribe-title": "Абониране за известия и новини от Podkrepi.bg", - "subscribe-campaign-title": "Абониране за известия по тази кампания" + "confirm-sent": "Моля, активирай абонамента си от email-a, който ти изпратихме на {{email}}", + "confirm-subscribe": "Записа се успешно.", + "subscribe-title": "Абониране за новините на Подкрепи.бг", + "subscribe-campaign-title": "Абониране за новините по кампанията", + "subscribe-text-nonLoggedUser": "Моля, продължи като гост и въведи email адреса, на който желаеш да получаваш известия за тази кампания, или влез в профила си. Вписвайки се с потребителското си име и парола, ще можеш да управляваш абонамента си от своя Личен профил.", + "subscribe-text-nonLoggedUser-general": "Моля, продължи като гост и въведи email адреса, на който желаеш да получаваш известия от нас, или влез в профила си. Вписвайки се с потребителското си име и парола, ще можеш да управляваш абонамента си от своя Личен профил.", + "subscribe-text-loggedUser": "Моля, избери дали желаеш да получаваш новините за кампанията на email адреса, асоцииран с профила ти, или на алтернативен адрес:", + "subscribe-subtitle": "Искам да получавам новини и известия от Подкрепи.бг на този email адрес:", + "subscribe-campaign-subtTitle": "Искам да получавам новини за кампанията на този email адрес:", + "subscribe-button": "Запиши ме", + "profile-button": "На профилния", + "another-button": "На друг" }, "campaign": { "subheading": "Вашата подкрепа променя света и има значение. Всички подкрепящи чрез Подкрепи.бг са наши партньори в подпомагането на кампании за общността. Като щедър дарител Вие ставате важен партньор в подпомагането на кампания за нечие здраве или за успеха на кауза, която ви е близка до сърцето.", diff --git a/public/locales/bg/index.json b/public/locales/bg/index.json index e2d2e6ef3..732554929 100644 --- a/public/locales/bg/index.json +++ b/public/locales/bg/index.json @@ -10,6 +10,10 @@ "content": "Подкрепи.бг представлява общност от специалисти в областта на програмирането, правото, маркетинга, дизайна, медицината, финансите, социалното предприемачество и др. Обединени сме от целта да създадем устойчива и прозрачна платформа за дарения, която подкрепя каузи и хора в нужда, като заедно с това популяризира и връща доверието към дарителството в България.", "meet-our-team": "Запознайте се с екипа ни" }, + "subscription-section": { + "heading": "Искаш да си в час с бъдещите ни постижения?", + "content": "Абонирай се за нашия бюлетин и ние ще те информираме за най-важното от живота на Подкрепи.бг. Всеки месец ще получваш email от нас, в който ще ти споделяме най-интересното за кампаниите, които поддържаме, както и за техните организатори и бенефициенти. Ще получаваш новините за нашите партньори, доброволци и дарители в електронната си пощенска кутия. Ако ти звучи добре, запиши се, като въведеш email адреса си тук:" + }, "support-us-section": { "heading": "Подкрепете ни като:", "financial-support": "- дарител", diff --git a/public/locales/bg/notifications.json b/public/locales/bg/notifications.json index b65e5c755..6a1a3a9fa 100644 --- a/public/locales/bg/notifications.json +++ b/public/locales/bg/notifications.json @@ -1,7 +1,9 @@ { "subscribe": { - "thank-you-msg": "Абонирането за получаване на известия e успешно! Благодарим ❤️", - "subscription-fail": "Възникна проблем при потвърджаването на абонамента за известия 🙄", + "thank-you-msg-heading": "Абонаментът ти е активен!", + "thank-you-msg-text": "Успешно активира своя абонамент. Очаквай новини от нас на {{email}}", + "subscription-fail-heading": "Възникна грешка", + "subscription-fail-text": "Не успяхме да активираме абонамента ти. Моля, опитай пак.", "cta": "Към сайта", "cta-retry": "Опитай пак" }, diff --git a/public/locales/bg/profile.json b/public/locales/bg/profile.json index 6de138c5f..d6e713daf 100644 --- a/public/locales/bg/profile.json +++ b/public/locales/bg/profile.json @@ -56,7 +56,6 @@ "refund": "възстановено", "cancelled": "отменено", "guaranteed": "гарантирано" - } }, "certificates-history": { diff --git a/public/locales/bg/validation.json b/public/locales/bg/validation.json index 3018432bb..ef89b0927 100644 --- a/public/locales/bg/validation.json +++ b/public/locales/bg/validation.json @@ -16,6 +16,7 @@ "agree-terms": "Съгласявам се с Общите условия", "agree-with": "Съгласявам се с", "agree-with-newsletter": "Съгласявам се да получавам известия ", + "agree-with-newsletter-campaign": "Съгласявам се да получавам новини за тази кампания и известия от Подкрепи.бг *", "informed-agree-with": "Запознат съм и се съгласявам с", "terms-and-conditions": "общите условия", "gdpr": "политиката за защита на личните данни", diff --git a/public/locales/en/auth.json b/public/locales/en/auth.json index 0e11270fb..8fb087a09 100644 --- a/public/locales/en/auth.json +++ b/public/locales/en/auth.json @@ -11,6 +11,7 @@ }, "cta": { "login": "Login", + "guest": "As guest", "logout": "Logout", "register": "Register", "send": "Send", @@ -18,6 +19,7 @@ }, "fields": { "email": "Email", + "email-descriptive": "Fill in your email", "password": "Password", "confirm-password": "Confirm Password", "first-name": "First name", diff --git a/public/locales/en/campaigns.json b/public/locales/en/campaigns.json index ae5a7165a..b90164eb7 100644 --- a/public/locales/en/campaigns.json +++ b/public/locales/en/campaigns.json @@ -74,6 +74,14 @@ "save": "Save", "submit": "Submit", "apply": "Apply", + "subscribe": "Subscribe for email notifications for the campaign", + "subscribeFooter": "Subscribe for the newsletter", + "subscribeGeneral": "Subscribe for email notifications from Podkrepi.bg", + "subscribe-monthly-newsletter": "Monthly newsletter of Podkrepi.bg", + "subscribeGeneralSubtext": "Receive our monthly newsletter which will inform you about the most interesting news from Podkrepi.bg!!", + "subscribe-general-monthly-newsletter": "Receive our monthly newsletter so that you are aware of the most interesting news from Podkrepi.bg!", + "subscribeGeneralButton": "Subscribe for news", + "subscribe-general-newsletter-button": "Subscribe", "support": "Donate", "support-cause-today": "Support a campaign today!", "support-now": "Support now", @@ -93,6 +101,20 @@ "attached-files": "Attached files", "download": "Download" }, + "subscribe": { + "confirm-sent": "Please, activate your subscription from the email that we sent to {{email}}", + "confirm-subscribe": "You subscribed successfully", + "subscribe-title": "Subscribe for news from Podkrepi.bg", + "subscribe-campaign-title": "Subscribe for news about the campaign", + "subscribe-text-nonLoggedUser": "Please, proceed as a guest and write down your email, on which you want to receive notifications for this campaign or you can log in. If you log in with your and password you will be able to manage your subscription from your Personal profile", + "subscribe-text-nonLoggedUser-general": "Please, proceed as a guest and write down your email, on which you want to receive notifications from us or you can log in. If you log in with your and password you will be able to manage your subscription from your Personal profile", + "subscribe-text-loggedUser": "Please, choose if you want to receive the news about the campaign on your profile email or on another one:", + "subscribe-subtitle": "I want to receive news and notifications from Podkrepi.bg on this email:", + "subscribe-campaign-subtTitle": "I want to receive news about the campaign on this email:", + "subscribe-button": "Subscribe me", + "profile-button": "On the profile one", + "another-button": "On another one" + }, "campaign": { "subheading": "Your support for the world matters. All supporters through Podkrepi.bg are our partners in supporting the community campaign. As a generous benefactor, you become an important partner in supporting a campaign regarding someone's health or the success of a cause that is close to your heart.", "subheading-bold": "Even the slightest help can be the engine of great change", diff --git a/public/locales/en/index.json b/public/locales/en/index.json index bc92241a8..2f546d6c5 100644 --- a/public/locales/en/index.json +++ b/public/locales/en/index.json @@ -10,6 +10,10 @@ "content": "Podkrepi.bg is a community of specialists in the field of programming, law, marketing, design, medicine, finance, social entrepreneurship and others. We are united by the goal of creating a sustainable and transparent donation platform that supports causes and people in need, while promoting and restoring trust in donations in Bulgaria.", "meet-our-team": "Meet our team" }, + "subscription-section": { + "heading": "You want to know about our future achievements?", + "content": "Subscribe for our newsletter we will infrom you about the most important from the life of Podkrepi.bg. Every month you will receive email from us in which we will share with you the most important things about the campaigns that we have and their organizers and beneficiaries. You will receive news for our partners, volunteers and donors in your email box. If this sounds good for you, subscribe as you fill in your email here:" + }, "support-us-section": { "heading": "Support us as:", "financial-support": "- a benefactor", diff --git a/public/locales/en/notifications.json b/public/locales/en/notifications.json new file mode 100644 index 000000000..3d9f6a360 --- /dev/null +++ b/public/locales/en/notifications.json @@ -0,0 +1,16 @@ +{ + "subscribe": { + "thank-you-msg-heading": "Your subscription is active!", + "thank-you-msg-text": "You successfully activated your subscription. You can wait news from us on {{email}}", + "subscription-fail-heading": "An error occurred", + "subscription-fail-text": "We couldn`t activate your subscription. Please, try again.", + "cta": "To the site", + "cta-retry": "Try again" + }, + "unsubscribe": { + "thank-you-msg": "You successfully deactivated your news subscription!", + "subscription-fail": "An error occurred while deactivating your news subscription", + "cta": "To the site", + "cta-retry": "Try again" + } +} diff --git a/public/locales/en/validation.json b/public/locales/en/validation.json index a91ffb1ac..4e1a9592e 100644 --- a/public/locales/en/validation.json +++ b/public/locales/en/validation.json @@ -16,6 +16,8 @@ "agree-terms": "Agree to the Terms and Conditions", "agree-with": "I agree to the", "informed-agree-with": "I understand and I agree to the", + "agree-with-newsletter": "I agree to receive news", + "agree-with-newsletter-campaign": "I agree to receive news about this campaign and news by Podkrepi.bg *", "terms-and-conditions": "Terms and Conditions", "gdpr": "General Data Protection Regulation (GDPR)", "legal-entity": "Legal entity", diff --git a/src/components/client/auth/register/CorporateRegisterForm.tsx b/src/components/client/auth/register/CorporateRegisterForm.tsx index 3418905cb..35b1e2caa 100644 --- a/src/components/client/auth/register/CorporateRegisterForm.tsx +++ b/src/components/client/auth/register/CorporateRegisterForm.tsx @@ -9,7 +9,7 @@ import PasswordField from 'components/common/form/PasswordField' import AcceptPrivacyPolicyField from 'components/common/form/AcceptPrivacyPolicyField' import AcceptTermsField from 'components/common/form/AcceptTermsField' import EmailField from 'components/common/form/EmailField' -import AcceptNewsLetterField from 'components/common/form/AcceptNewsletterField' +import { AcceptNewsLetterField } from 'components/common/form/AcceptNewsletterField' import { AccountType } from 'gql/user-registration' import { validateEIK13, validateEIK9 } from 'components/common/validations/EIKValidator' diff --git a/src/components/client/auth/register/RegisterForm.tsx b/src/components/client/auth/register/RegisterForm.tsx index b56f2a08c..5ee114f58 100644 --- a/src/components/client/auth/register/RegisterForm.tsx +++ b/src/components/client/auth/register/RegisterForm.tsx @@ -9,7 +9,7 @@ import PasswordField from 'components/common/form/PasswordField' import AcceptPrivacyPolicyField from 'components/common/form/AcceptPrivacyPolicyField' import AcceptTermsField from 'components/common/form/AcceptTermsField' import EmailField from 'components/common/form/EmailField' -import AcceptNewsLetterField from 'components/common/form/AcceptNewsletterField' +import { AcceptNewsLetterField } from 'components/common/form/AcceptNewsletterField' import { AccountType } from 'gql/user-registration' import { IndividualRegisterFormData } from 'gql/user-registration' diff --git a/src/components/client/campaigns/CampaignDetails.tsx b/src/components/client/campaigns/CampaignDetails.tsx index f60bd78c1..6cf7451e6 100644 --- a/src/components/client/campaigns/CampaignDetails.tsx +++ b/src/components/client/campaigns/CampaignDetails.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' import { useTranslation } from 'next-i18next' import dynamic from 'next/dynamic' @@ -26,6 +26,8 @@ import { routes } from 'common/routes' import { useCanEditCampaign } from 'common/hooks/campaigns' import { moneyPublic } from 'common/util/money' import CampaignPublicExpensesChart from './CampaignPublicExpensesChart' +import EmailIcon from '@mui/icons-material/Email' +import RenderCampaignSubscribeModal from '../notifications/CampaignSubscribeModal' const ReactQuill = dynamic(() => import('react-quill'), { ssr: false }) const CampaignNewsSection = dynamic(() => import('./CampaignNewsSection'), { ssr: false }) @@ -37,6 +39,7 @@ const classes = { campaignTitle: `${PREFIX}-campaignTitle`, linkButton: `${PREFIX}-linkButton`, securityIcon: `${PREFIX}-securityIcon`, + subscribeLink: `${PREFIX}-subscribe`, financeSummary: `${PREFIX}-financeSummary`, } @@ -93,7 +96,18 @@ const StyledGrid = styled(Grid)(({ theme }) => ({ width: theme.spacing(2.25), height: theme.spacing(2.75), }, + [`& .${classes.subscribeLink}`]: { + fontWeight: 500, + fontSize: theme.typography.pxToRem(16.5), + textAlign: 'center', + '&:hover': { + textDecoration: 'underline', + transform: 'scale(1.01)', + cursor: 'pointer', + transition: 'all 0.3s ease', + }, + }, [`& .${classes.financeSummary}`]: { fontSize: `1.2rem`, [theme.breakpoints.up('sm')]: { @@ -109,6 +123,7 @@ type Props = { export default function CampaignDetails({ campaign }: Props) { const { t } = useTranslation() + const [subscribeIsOpen, setSubscribeOpen] = useState(false) const sliderImages = campaignSliderUrls(campaign) const canEditCampaign = useCanEditCampaign(campaign.slug) const { data: expensesList } = useCampaignApprovedExpensesList(campaign.slug) @@ -124,7 +139,22 @@ export default function CampaignDetails({ campaign }: Props) { showExpensesLink={(expensesList && expensesList?.length > 0) || canEditCampaign} /> - + {subscribeIsOpen && ( + + )} + + setSubscribeOpen(true)} + cursor="pointer" + /> + setSubscribeOpen(true)} className={classes.subscribeLink}> + {t('campaigns:cta.subscribe')} + + + @@ -172,6 +202,21 @@ export default function CampaignDetails({ campaign }: Props) { )} + {subscribeIsOpen && ( + + )} + + setSubscribeOpen(true)} + cursor="pointer" + /> + setSubscribeOpen(true)} className={classes.subscribeLink}> + {t('campaigns:cta.subscribe')} + + diff --git a/src/components/client/campaigns/InlineDonation.tsx b/src/components/client/campaigns/InlineDonation.tsx index 6374c62ab..c41e32b6a 100644 --- a/src/components/client/campaigns/InlineDonation.tsx +++ b/src/components/client/campaigns/InlineDonation.tsx @@ -36,11 +36,11 @@ import LinkButton from '../../common/LinkButton' import CampaignProgress from './CampaignProgress' import DonorsAndDonations from './DonorsAndDonations' import DonationWishesInline from './DonationWishesInline' + import CustomListItem from 'components/common/navigation/CustomListItem' import { socialMedia } from './helpers/socialMedia' import { CampaignState } from './helpers/campaign.enums' import { AlertStore } from 'stores/AlertStore' -import RenderCampaignSubscribeModal from '../notifications/CampaignSubscribeModal' import { useDonationWishesList } from 'common/hooks/donationWish' const PREFIX = 'InlineDonation' @@ -66,7 +66,6 @@ const classes = { campaignInfoKey: `${PREFIX}-campaignInfoKey`, campaignInfoValue: `${PREFIX}-campaignInfoValue`, pagination: `${PREFIX}-pagination`, - subscribeLink: `${PREFIX}-subscribe`, } const StyledGrid = styled(Grid)(({ theme }) => ({ @@ -243,19 +242,6 @@ const StyledGrid = styled(Grid)(({ theme }) => ({ fontSize: theme.typography.pxToRem(15), }, }, - - [`& .${classes.subscribeLink}`]: { - fontWeight: 500, - fontSize: theme.typography.pxToRem(16.5), - textAlign: 'center', - - '&:hover': { - textDecoration: 'underline', - transform: 'scale(1.01)', - cursor: 'pointer', - transition: 'all 0.3s ease', - }, - }, })) type Props = { @@ -266,7 +252,6 @@ export default function InlineDonation({ campaign }: Props) { const { t } = useTranslation('campaigns') const { asPath } = useRouter() const [status, copyUrl] = useCopyToClipboard(1000) - const [subscribeIsOpen, setSubscribeOpen] = useState(false) const active = status === 'copied' ? 'inherit' : 'primary' const [page, setPage] = useState(0) const { mobile } = useMobile() @@ -439,22 +424,6 @@ export default function InlineDonation({ campaign }: Props) { - {subscribeIsOpen && ( - - )} - {/* Hide until notifications is ready */} - {/* - setSubscribeOpen(true)} className={classes.subscribeLink}> - {t('campaigns:cta.subscribe')} - - setSubscribeOpen(true)} cursor="pointer" /> - */} {detailsShown && (donationHistoryError ? ( 'Error fetching donation history' diff --git a/src/components/client/index/IndexPage.tsx b/src/components/client/index/IndexPage.tsx index 9917614b0..819b2bc95 100644 --- a/src/components/client/index/IndexPage.tsx +++ b/src/components/client/index/IndexPage.tsx @@ -7,6 +7,7 @@ import PlatformStatisticsSection from './sections/PlatformStatisticsSection/Plat import MediaSection from './sections/MediaSection/MediaSection' import HowWeWorkSection from './sections/HowWeWorkSection/HowWeWorkSection' import PartnersSection from './sections/PartnersSection/PartnersSection' +import SubscriptionSection from './sections/SubscriptionSection/SubscriptionSection' import TeamMembersSection from './sections/TeamMembersSection/TeamMembersSection' import JoinPodkrepiBgSection from './sections/JoinPodkrepiBgSection/JoinPodkrepiBgSection' import FaqSection from './sections/FaqSection/FaqSection' @@ -28,6 +29,7 @@ export default function IndexPage() { + ) diff --git a/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.styled.tsx b/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.styled.tsx index c24d71384..51c99674e 100644 --- a/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.styled.tsx +++ b/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.styled.tsx @@ -1,4 +1,4 @@ -import { Typography, Grid } from '@mui/material' +import { Button, Typography, Grid } from '@mui/material' import { styled } from '@mui/material/styles' import theme from 'common/theme' @@ -73,3 +73,33 @@ export const HelpThoseInNeedButton = styled(LinkButton)(() => ({ }, }, })) + +export const SubscribeHeading = styled(Typography)(() => ({ + fontWeight: 500, + fontSize: theme.typography.pxToRem(16.5), + textAlign: 'center', +})) + +export const SubscribeButton = styled(Button)(() => ({ + fontWeight: 600, + borderRadius: theme.borders.round, + backgroundColor: theme.palette.secondary.main, + minWidth: theme.spacing(3.75), + fontSize: theme.typography.pxToRem(15), + margin: theme.spacing(2, 0, 0, 'auto'), + boxShadow: + '0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px rgba(0, 0, 0, 0.14), 0px 1px 5px rgba(0, 0, 0, 0.12)', + + '& span': { + display: 'none', + }, + + [theme.breakpoints.up('md')]: { + fontSize: theme.typography.pxToRem(17), + minWidth: theme.spacing(50), + + '& span': { + display: 'inline-flex', + }, + }, +})) diff --git a/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.tsx b/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.tsx index b10ed3359..4fe900a49 100644 --- a/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.tsx +++ b/src/components/client/index/sections/PlatformStatisticsSection/PlatformStatisticsSection.tsx @@ -1,8 +1,9 @@ -import React from 'react' +import React, { useState } from 'react' import { useTranslation } from 'next-i18next' -import ArrowForwardSharp from '@mui/icons-material/ArrowForwardSharp' import { Grid } from '@mui/material' +import ArrowForwardSharp from '@mui/icons-material/ArrowForwardSharp' +import EmailIcon from '@mui/icons-material/Email' import { routes } from 'common/routes' import Statistics from './Statistics/Statistics' @@ -13,10 +14,14 @@ import { Root, SectionGridWrapper, Subtitle, + SubscribeButton, + SubscribeHeading, } from './PlatformStatisticsSection.styled' +import RenderSubscribeModal from 'components/client/notifications/GeneralSubscribeModal' export default function PlatformStatisticsSection() { - const { t } = useTranslation('index') + const { t } = useTranslation() + const [subscribeIsOpen, setSubscribeOpen] = useState(false) return ( @@ -26,14 +31,26 @@ export default function PlatformStatisticsSection() { margin: '0 auto', maxWidth: theme.spacing(67), })}> - {t('platform-statistics.heading')} - {t('platform-statistics.text')} + {t('index:platform-statistics.heading')} + {t('index:platform-statistics.text')} }> - {t('platform-statistics.donate-to-those-in-need')} + {t('index:platform-statistics.donate-to-those-in-need')} + {subscribeIsOpen && } + + + {t('campaigns:cta.subscribeGeneral')} + + {t('campaigns:cta.subscribeGeneralSubtext')} + setSubscribeOpen(true)} + variant="contained" + endIcon={}> + {t('campaigns:cta.subscribeGeneralButton')} + diff --git a/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.styled.tsx b/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.styled.tsx new file mode 100644 index 000000000..b10a43bfb --- /dev/null +++ b/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.styled.tsx @@ -0,0 +1,28 @@ +import { Grid, Typography } from '@mui/material' +import { styled } from '@mui/material/styles' + +import theme from 'common/theme' + +export const InfoText = styled(Typography)(() => ({ + textAlign: 'center', + fontSize: theme.typography.pxToRem(16), + lineHeight: theme.spacing(3), + padding: theme.spacing(0, 8, 6, 8), +})) + +export const SubscribeGrid = styled(Grid)(() => ({ + margin: theme.spacing(4, 'auto'), + + [`& .subscribeBtn`]: { + fontSize: theme.typography.pxToRem(16), + background: `${theme.palette.primary}`, + + '&:hover': { + background: theme.palette.primary.main, + }, + }, + + [theme.breakpoints.up(768)]: { + margin: theme.spacing(8, 'auto'), + }, +})) diff --git a/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.tsx b/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.tsx new file mode 100644 index 000000000..9b2190a23 --- /dev/null +++ b/src/components/client/index/sections/SubscriptionSection/SubscriptionSection.tsx @@ -0,0 +1,62 @@ +import React, { useState } from 'react' +import { useTranslation } from 'next-i18next' +import { Heading } from '../../IndexPage.styled' +import { InfoText } from './SubscriptionSection.styled' +import { Grid } from '@mui/material' +import ArrowForwardSharp from '@mui/icons-material/ArrowForwardSharp' +import EmailIcon from '@mui/icons-material/Email' +import RenderSubscribeModal from 'components/client/notifications/GeneralSubscribeModal' +import { + SectionGridWrapper, + SubscribeButton, + SubscribeHeading, + Subtitle, +} from '../PlatformStatisticsSection/PlatformStatisticsSection.styled' + +export type SubscribeToNotificationsInput = { + email: string +} + +const SubscriptionSection = () => { + const { t } = useTranslation() + const [subscribeIsOpen, setSubscribeOpen] = useState(false) + + return ( + ({ + marginBottom: theme.spacing(5), + })}> + ({ + margin: '0 auto', + maxWidth: theme.spacing(95), + textAlign: 'center', + })}> + {t('index:subscription-section.heading')} + {t('index:subscription-section.content')} + {subscribeIsOpen && } + + setSubscribeOpen(true)} + cursor="pointer" + /> + setSubscribeOpen(true)}> + {t('campaigns:cta.subscribe-monthly-newsletter')} + + + {t('campaigns:cta.subscribe-general-monthly-newsletter')} + setSubscribeOpen(true)} + variant="contained" + endIcon={}> + {t('campaigns:cta.subscribe-general-newsletter-button')} + + + + ) +} + +export default SubscriptionSection diff --git a/src/components/client/index/sections/TeamMembersSection/TeamMembersSection.tsx b/src/components/client/index/sections/TeamMembersSection/TeamMembersSection.tsx index 4b38e2eaa..5ca93f554 100644 --- a/src/components/client/index/sections/TeamMembersSection/TeamMembersSection.tsx +++ b/src/components/client/index/sections/TeamMembersSection/TeamMembersSection.tsx @@ -1,13 +1,13 @@ -import React from 'react' +import React, { useState } from 'react' import Image from 'next/image' import { useTranslation } from 'next-i18next' import ChevronRightIcon from '@mui/icons-material/ChevronRight' import { Box, Grid } from '@mui/material' - import { routes } from 'common/routes' import { Heading, InfoText, OutlinedButton } from '../../IndexPage.styled' import { Root } from './TeamMembersSection.styled' +import { SectionGridWrapper } from '../PlatformStatisticsSection/PlatformStatisticsSection.styled' export default function TeamMembersSection() { const { t } = useTranslation('index') @@ -27,11 +27,9 @@ export default function TeamMembersSection() { /> {/* A11Y TODO: Translate alt text */} - - }> - {t('team-section.meet-our-team')} - - + }> + {t('team-section.meet-our-team')} + ) } diff --git a/src/components/client/layout/Footer/Footer.styled.tsx b/src/components/client/layout/Footer/Footer.styled.tsx index 3e23b93ad..2be5e2134 100644 --- a/src/components/client/layout/Footer/Footer.styled.tsx +++ b/src/components/client/layout/Footer/Footer.styled.tsx @@ -75,3 +75,12 @@ export const SubscribeLinkWrapper = styled(Grid)(({ theme }) => ({ transition: 'all 0.3s ease', }, })) + +export const SubscriptionTitle = styled(Typography)(() => ({ + '&:hover': { + textDecoration: 'underline', + transform: 'scale(1.01)', + cursor: 'pointer', + transition: 'all 0.3s ease', + }, +})) diff --git a/src/components/client/layout/Footer/LogoSocialIcons.tsx b/src/components/client/layout/Footer/LogoSocialIcons.tsx index 5460efe7b..5d1efb84a 100644 --- a/src/components/client/layout/Footer/LogoSocialIcons.tsx +++ b/src/components/client/layout/Footer/LogoSocialIcons.tsx @@ -6,7 +6,6 @@ import { Grid } from '@mui/material' import { routes } from 'common/routes' import PodkrepiLogo from 'components/common/brand/PodkrepiLogo' import { SocialIcons } from './SocialIcons' -// import { SubscribeBtn } from './SubscribeBtn' export const LogoSocialIcons = () => { const { locale } = useRouter() @@ -20,8 +19,6 @@ export const LogoSocialIcons = () => { - {/* Hide until notifications is ready */} - {/* */} ) } diff --git a/src/components/client/layout/Footer/SocialIcons.tsx b/src/components/client/layout/Footer/SocialIcons.tsx index 0894ee91b..15804174f 100644 --- a/src/components/client/layout/Footer/SocialIcons.tsx +++ b/src/components/client/layout/Footer/SocialIcons.tsx @@ -5,6 +5,7 @@ import ExternalLink from 'components/common/ExternalLink' import { useTranslation } from 'next-i18next' import { SocialIconsWrapper } from './Footer.styled' +import Subscription from './Subscription' export const SocialIcons = () => { const { t } = useTranslation() @@ -25,6 +26,7 @@ export const SocialIcons = () => { aria-label={t('components.footer.social.instagram')}> + ) } diff --git a/src/components/client/layout/Footer/Subscription.tsx b/src/components/client/layout/Footer/Subscription.tsx new file mode 100644 index 000000000..8bf5afe7c --- /dev/null +++ b/src/components/client/layout/Footer/Subscription.tsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react' +import { useTranslation } from 'next-i18next' + +import { Grid } from '@mui/material' +import EmailIcon from '@mui/icons-material/Email' + +import RenderSubscribeModal from 'components/client/notifications/GeneralSubscribeModal' +import { SubscriptionTitle } from './Footer.styled' + +export default function Subscription() { + const { t } = useTranslation() + const [subscribeIsOpen, setSubscribeOpen] = useState(false) + + return ( + + {subscribeIsOpen && } + setSubscribeOpen(true)} + cursor="pointer" + /> + setSubscribeOpen(true)}> + {t('campaigns:cta.subscribeFooter')} + + + ) +} diff --git a/src/components/client/notifications/CampaignSubscribeModal.tsx b/src/components/client/notifications/CampaignSubscribeModal.tsx index ab029399a..88a626a6e 100644 --- a/src/components/client/notifications/CampaignSubscribeModal.tsx +++ b/src/components/client/notifications/CampaignSubscribeModal.tsx @@ -1,23 +1,26 @@ +import React, { useState } from 'react' import * as yup from 'yup' -import { email } from 'common/form/validation' +import { Trans } from 'react-i18next' import { useTranslation } from 'next-i18next' -import { useState } from 'react' +import { useMutation } from '@tanstack/react-query' +import { useSession } from 'next-auth/react' import { AxiosError, AxiosResponse } from 'axios' import { ApiError } from 'next/dist/server/api-utils' +import { useRouter } from 'next/router' import { AlertStore } from 'stores/AlertStore' import { useSubscribeToCampaign } from 'service/notification' import { CampaignResponse, CampaignSubscribeInput, CampaignSubscribeResponse } from 'gql/campaigns' -import { useMutation } from '@tanstack/react-query' -import { Dialog, DialogContent, DialogTitle, Grid } from '@mui/material' +import { Dialog, DialogContent, DialogTitle, Grid, Typography } from '@mui/material' +import EmailIcon from '@mui/icons-material/Email' +import ThumbUpIcon from '@mui/icons-material/ThumbUp' +import { styled } from '@mui/material/styles' import CloseModalButton from 'components/common/CloseModalButton' import GenericForm from 'components/common/form/GenericForm' -import { styled } from '@mui/material/styles' import SubmitButton from 'components/common/form/SubmitButton' import EmailField from 'components/common/form/EmailField' -import AcceptNewsLetterField from 'components/common/form/AcceptNewsletterField' -import { useSession } from 'next-auth/react' -import { getCurrentPerson } from 'common/util/useCurrentPerson' -import React from 'react' +import { email } from 'common/form/validation' +import { AcceptNewsLetterFieldCampaign } from 'components/common/form/AcceptNewsletterField' +import { routes } from 'common/routes' const PREFIX = 'CampaignSubscribeModal' @@ -28,14 +31,7 @@ const classes = { const StyledGrid = styled(Grid)(({ theme }) => ({ [`& .${classes.subscribeBtn}`]: { fontSize: theme.typography.pxToRem(16), - background: `${theme.palette.secondary.main}`, - - '&:hover': { - background: theme.palette.primary.main, - }, - '& svg': { - color: '#ab2f26', - }, + background: `${theme.palette.primary}`, }, })) @@ -60,9 +56,12 @@ const validationSchema: yup.SchemaOf = yup export default function RenderCampaignSubscribeModal({ campaign, setOpen }: ModalProps) { const { t } = useTranslation() const { status } = useSession() - const [loading, setLoading] = useState(false) const [isSuccess, setIsSuccess] = useState(false) + const [isGuest, setIsGuest] = useState(false) + const [email, setEmail] = useState('') + const [consent, setConsent] = useState(false) + const router = useRouter() const handleError = (e: AxiosError) => { const error = e.response?.data?.message @@ -75,7 +74,11 @@ export default function RenderCampaignSubscribeModal({ campaign, setOpen }: Moda CampaignSubscribeInput >({ mutationFn: useSubscribeToCampaign(campaign.id), - onError: (error) => handleError(error), + onError: (error) => { + console.log(error.message) + + handleError(error) + }, onSuccess: () => { AlertStore.show(t('common:alerts.message-sent'), 'success') @@ -89,6 +92,8 @@ export default function RenderCampaignSubscribeModal({ campaign, setOpen }: Moda async function onSubmit(values: { email: string; consent: boolean }) { setLoading(true) + setEmail(values.email) + setConsent(values.consent) try { await mutation.mutateAsync(values) } finally { @@ -96,35 +101,7 @@ export default function RenderCampaignSubscribeModal({ campaign, setOpen }: Moda } } - function AuthenticatedForm() { - const { data: user } = getCurrentPerson() - - return ( - - - {/* Show consent checkbox if user has not provided it previously */} - {!user?.user?.newsletter && ( - - - - )} - - - - - - ) - } - - function NonAuthenticatedForm() { + const NonAuthenticatedForm = () => { return ( - + + {t('campaigns:subscribe.subscribe-campaign-subtTitle')} + - - + + + + + @@ -150,36 +132,127 @@ export default function RenderCampaignSubscribeModal({ campaign, setOpen }: Moda ) } - return ( - - - + const openAsGuest = () => { + setIsGuest(true) + } + + const sendOnProfileEmail = (status: string) => { + if (status !== 'authenticated') { + router.push(routes.login) + } else { + onSubmit({ email: email || '', consent: consent || true }) + handleClose() + } + } + + if (!isGuest) { + return ( + + - - {!isSuccess ? ( + {t('campaigns:subscribe.subscribe-campaign-title')} - {status === 'authenticated' ? : } + + + + {status !== 'authenticated' + ? t('campaigns:subscribe.subscribe-text-nonLoggedUser') + : t('campaigns:subscribe.subscribe-text-loggedUser')} + + + + sendOnProfileEmail(status)} + /> + openAsGuest()} + /> + + - ) : ( - - {status === 'authenticated' - ? t('campaigns:subscribe.confirm-subscribe') - : t('campaigns:subscribe.confirm-sent')} - - )} - - - ) + + + ) + } else { + return ( + + + + {!isSuccess ? ( + + + + {t('campaigns:subscribe.subscribe-campaign-title')} + + + + + + ) : ( + + + + + + + {t('campaigns:subscribe.confirm-subscribe')} + + + + + + + + )} + + + ) + } } diff --git a/src/components/client/notifications/GeneralSubscribeModal.tsx b/src/components/client/notifications/GeneralSubscribeModal.tsx index b35cc42fb..40f0a7a91 100644 --- a/src/components/client/notifications/GeneralSubscribeModal.tsx +++ b/src/components/client/notifications/GeneralSubscribeModal.tsx @@ -1,22 +1,29 @@ +import React, { useState } from 'react' import * as yup from 'yup' -import { email } from 'common/form/validation' +import { Trans } from 'react-i18next' import { useTranslation } from 'next-i18next' -import { useState } from 'react' +import { useMutation } from '@tanstack/react-query' +import { useSession } from 'next-auth/react' import { AxiosError, AxiosResponse } from 'axios' import { ApiError } from 'next/dist/server/api-utils' +import { useRouter } from 'next/router' import { AlertStore } from 'stores/AlertStore' -import { useMutation } from '@tanstack/react-query' -import { Dialog, DialogContent, DialogTitle, Grid } from '@mui/material' +import { Dialog, DialogContent, DialogTitle, Grid, Typography } from '@mui/material' +import EmailIcon from '@mui/icons-material/Email' +import ThumbUpIcon from '@mui/icons-material/ThumbUp' +import { styled } from '@mui/material/styles' import CloseModalButton from 'components/common/CloseModalButton' import GenericForm from 'components/common/form/GenericForm' -import { styled } from '@mui/material/styles' import SubmitButton from 'components/common/form/SubmitButton' import EmailField from 'components/common/form/EmailField' +import { email } from 'common/form/validation' +import { AcceptNewsLetterField } from 'components/common/form/AcceptNewsletterField' +import { routes } from 'common/routes' + import { useSendConfirmationEmail } from 'service/notification' import { SendConfirmationEmailResponse, SendConfirmationEmailInput } from 'gql/notification' -import React from 'react' -const PREFIX = 'SubscribeModal' +const PREFIX = 'GeneralSubscribeModal' const classes = { subscribeBtn: `${PREFIX}-subscribe`, @@ -25,7 +32,7 @@ const classes = { const StyledGrid = styled(Grid)(({ theme }) => ({ [`& .${classes.subscribeBtn}`]: { fontSize: theme.typography.pxToRem(16), - background: `${theme.palette.secondary.main}`, + background: `${theme.palette.primary}`, '&:hover': { background: theme.palette.primary.main, @@ -42,17 +49,26 @@ interface ModalProps { export type SubscribeToNotificationsInput = { email: string + consent: boolean } -const validationSchema: yup.SchemaOf = yup.object().defined().shape({ - email: email.required(), -}) +const validationSchema: yup.SchemaOf = yup + .object() + .defined() + .shape({ + email: email.required(), + consent: yup.bool().required().oneOf([true], 'validation:newsletter'), + }) export default function RenderSubscribeModal({ setOpen }: ModalProps) { const { t } = useTranslation() + const { status } = useSession() const [loading, setLoading] = useState(false) const [isSuccess, setIsSuccess] = useState(false) + const [isGuest, setIsGuest] = useState(false) + const [email, setEmail] = useState('') + const router = useRouter() const handleError = (e: AxiosError) => { const error = e.response?.data?.message @@ -79,6 +95,7 @@ export default function RenderSubscribeModal({ setOpen }: ModalProps) { async function onSubmit(values: { email: string }) { setLoading(true) + setEmail(values.email) try { await mutation.mutateAsync(values) } finally { @@ -86,21 +103,29 @@ export default function RenderSubscribeModal({ setOpen }: ModalProps) { } } - function SubscribeForm() { + const SubscribeForm = () => { return ( - + + {t('campaigns:subscribe.subscribe-subtitle')} + + + + + + + @@ -109,34 +134,127 @@ export default function RenderSubscribeModal({ setOpen }: ModalProps) { ) } - return ( - - - + const openAsGuest = () => { + setIsGuest(true) + } + + const sendOnProfileEmail = (status: string) => { + if (status !== 'authenticated') { + router.push(routes.login) + } else { + onSubmit({ email: email || '' }) + handleClose() + } + } + + if (!isGuest) { + return ( + + - - {!isSuccess ? ( + {t('campaigns:subscribe.subscribe-title')} - + + + + {status !== 'authenticated' + ? t('campaigns:subscribe.subscribe-text-nonLoggedUser-general') + : t('campaigns:subscribe.subscribe-text-loggedUser')} + + + + sendOnProfileEmail(status)} + /> + openAsGuest()} + /> + + - ) : ( - - {t('campaigns:subscribe.confirm-sent').split('{{email}}')} - - )} - - - ) + + + ) + } else { + return ( + + + + {!isSuccess ? ( + + + + {t('campaigns:subscribe.subscribe-title')} + + + + + + ) : ( + + + + + + + {t('campaigns:subscribe.confirm-subscribe')} + + + + + + + + )} + + + ) + } } diff --git a/src/components/client/notifications/SubscriptionPage.tsx b/src/components/client/notifications/SubscriptionPage.tsx index e0e5e26f1..aa73c8dce 100644 --- a/src/components/client/notifications/SubscriptionPage.tsx +++ b/src/components/client/notifications/SubscriptionPage.tsx @@ -1,8 +1,10 @@ -import { useTranslation } from 'next-i18next' +import { useTranslation, Trans } from 'react-i18next' import Layout from '../layout/Layout' import PodkrepiLogo from 'components/common/brand/PodkrepiLogo' import { useRouter } from 'next/router' -import { Button, DialogContent, Grid } from '@mui/material' +import { Button, DialogTitle, Grid, Typography } from '@mui/material' +import ThumbUpIcon from '@mui/icons-material/ThumbUp' +import AnnouncementIcon from '@mui/icons-material/Announcement' import { styled } from '@mui/material/styles' import LinkButton from 'components/common/LinkButton' import React, { useEffect, useState } from 'react' @@ -95,8 +97,6 @@ export default function SubscriptionPage(data: Props) { }, []) const handleError = (e: AxiosError) => { - const error = e.response?.data?.message - console.log(error) setLoading(false) setIsSuccess(false) } @@ -147,26 +147,44 @@ export default function SubscriptionPage(data: Props) { {isSuccess ? ( - - - {t('notifications:subscribe.thank-you-msg')} - + + + + + {t('notifications:subscribe.thank-you-msg-heading')} + + + + + {t('notifications:subscribe.cta')} - {' '} + ) : ( - - - {t('notifications:subscribe.subscription-fail')} - + + + + + {t('notifications:subscribe.subscription-fail-heading')} + + + + +