diff --git a/next-env.d.ts b/next-env.d.ts index 4f11a03dc..a4a7b3f5c 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/package-lock.json b/package-lock.json index 282c6f999..1ab66f786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4782,9 +4782,9 @@ "dev": true }, "node_modules/@graphql-tools/utils": { - "version": "10.5.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.5.5.tgz", - "integrity": "sha512-LF/UDWmMT0mnobL2UZETwYghV7HYBzNaGj0SAkCYOMy/C3+6sQdbcTksnoFaKR9XIVD78jNXEGfivbB8Zd+cwA==", + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.1.tgz", + "integrity": "sha512-XHl0/DWkMf/8Dmw1F3RRoMPt6ZwU4J707YWcbPjS+49WZNoTVz6f+prQ4GuwZT8RqTPtrRawnGU93AV73ZLTfQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/public/.well-known/apple-developer-merchantid-domain-association b/public/.well-known/apple-developer-merchantid-domain-association new file mode 100644 index 000000000..2ff95c962 --- /dev/null +++ b/public/.well-known/apple-developer-merchantid-domain-association @@ -0,0 +1 @@ +7B227073704964223A2239373943394538343346343131343044463144313834343232393232313734313034353044314339464446394437384337313531303944334643463542433731222C2276657273696F6E223A312C22637265617465644F6E223A313536363233343735303036312C227369676E6174757265223A22333038303036303932613836343838366637306430313037303261303830333038303032303130313331306633303064303630393630383634383031363530333034303230313035303033303830303630393261383634383836663730643031303730313030303061303830333038323033653333303832303338386130303330323031303230323038346333303431343935313964353433363330306130363038326138363438636533643034303330323330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333031653137306433313339333033353331333833303331333333323335333735613137306433323334333033353331333633303331333333323335333735613330356633313235333032333036303335353034303330633163363536333633326437333664373032643632373236663662363537323264373336393637366535663535343333343264353035323466343433313134333031323036303335353034306230633062363934663533323035333739373337343635366437333331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533333035393330313330363037326138363438636533643032303130363038326138363438636533643033303130373033343230303034633231353737656465626436633762323231386636386464373039306131323138646337623062643666326332383364383436303935643934616634613534313162383334323065643831316633343037653833333331663163353463336637656233323230643662616435643465666634393238393839336537633066313361333832303231313330383230323064333030633036303335353164313330313031666630343032333030303330316630363033353531643233303431383330313638303134323366323439633434663933653465663237653663346636323836633366613262626664326534623330343530363038326230363031303530353037303130313034333933303337333033353036303832623036303130353035303733303031383632393638373437343730336132663266366636333733373032653631373037303663363532653633366636643266366636333733373033303334326436313730373036633635363136393633363133333330333233303832303131643036303335353164323030343832303131343330383230313130333038323031306330363039326138363438383666373633363430353031333038316665333038316333303630383262303630313035303530373032303233303831623630633831623335323635366336393631366536333635323036663665323037343638363937333230363336353732373436393636363936333631373436353230363237393230363136653739323037303631373237343739323036313733373337353664363537333230363136333633363537303734363136653633363532303666363632303734363836353230373436383635366532303631373037303663363936333631363236633635323037333734363136653634363137323634323037343635373236643733323036313665363432303633366636653634363937343639366636653733323036663636323037353733363532633230363336353732373436393636363936333631373436353230373036663663363936333739323036313665363432303633363537323734363936363639363336313734363936663665323037303732363136333734363936333635323037333734363137343635366436353665373437333265333033363036303832623036303130353035303730323031313632613638373437343730336132663266373737373737326536313730373036633635326536333666366432663633363537323734363936363639363336313734363536313735373436383666373236393734373932663330333430363033353531643166303432643330326233303239613032376130323538363233363837343734373033613266326636333732366332653631373037303663363532653633366636643266363137303730366336353631363936333631333332653633373236633330316430363033353531643065303431363034313439343537646236666435373438313836383938393736326637653537383530376537396235383234333030653036303335353164306630313031666630343034303330323037383033303066303630393261383634383836663736333634303631643034303230353030333030613036303832613836343863653364303430333032303334393030333034363032323130306265303935373166653731653165373335623535653561666163623463373266656234343566333031383532323263373235313030326236316562643666353530323231303064313862333530613564643664643665623137343630333562313165623263653837636661336536616636636264383338303839306463383263646461613633333038323032656533303832303237356130303330323031303230323038343936643266626633613938646139373330306130363038326138363438636533643034303330323330363733313162333031393036303335353034303330633132343137303730366336353230353236663666373432303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330316531373064333133343330333533303336333233333334333633333330356131373064333233393330333533303336333233333334333633333330356133303761333132653330326330363033353530343033306332353431373037303663363532303431373037303663363936333631373436393666366532303439366537343635363737323631373436393666366532303433343132303264323034373333333132363330323430363033353530343062306331643431373037303663363532303433363537323734363936363639363336313734363936663665323034313735373436383666373236393734373933313133333031313036303335353034306130633061343137303730366336353230343936653633326533313062333030393036303335353034303631333032353535333330353933303133303630373261383634386365336430323031303630383261383634386365336430333031303730333432303030346630313731313834313964373634383564353161356532353831303737366538383061326566646537626165346465303864666334623933653133333536643536363562333561653232643039373736306432323465376262613038666437363137636538386362373662623636373062656338653832393834666635343435613338316637333038316634333034363036303832623036303130353035303730313031303433613330333833303336303630383262303630313035303530373330303138363261363837343734373033613266326636663633373337303265363137303730366336353265363336663664326636663633373337303330333432643631373037303663363537323666366637343633363136373333333031643036303335353164306530343136303431343233663234396334346639336534656632376536633466363238366333666132626266643265346233303066303630333535316431333031303166663034303533303033303130316666333031663036303335353164323330343138333031363830313462626230646561313538333338383961613438613939646562656264656261666461636232346162333033373036303335353164316630343330333032653330326361303261613032383836323636383734373437303361326632663633373236633265363137303730366336353265363336663664326636313730373036633635373236663666373436333631363733333265363337323663333030653036303335353164306630313031666630343034303330323031303633303130303630613261383634383836663736333634303630323065303430323035303033303061303630383261383634386365336430343033303230333637303033303634303233303361636637323833353131363939623138366662333563333536636136326266663431376564643930663735346461323865626566313963383135653432623738396638393866373962353939663938643534313064386639646539633266653032333033323264643534343231623061333035373736633564663333383362393036376664313737633263323136643936346663363732363938323132366635346638376137643162393963623962303938393231363130363939306630393932316430303030333138323031386233303832303138373032303130313330383138363330376133313265333032633036303335353034303330633235343137303730366336353230343137303730366336393633363137343639366636653230343936653734363536373732363137343639366636653230343334313230326432303437333333313236333032343036303335353034306230633164343137303730366336353230343336353732373436393636363936333631373436393666366532303431373537343638366637323639373437393331313333303131303630333535303430613063306134313730373036633635323034393665363332653331306233303039303630333535303430363133303235353533303230383463333034313439353139643534333633303064303630393630383634383031363530333034303230313035303061303831393533303138303630393261383634383836663730643031303930333331306230363039326138363438383666373064303130373031333031633036303932613836343838366637306430313039303533313066313730643331333933303338333133393331333733313332333333303561333032613036303932613836343838366637306430313039333433313164333031623330306430363039363038363438303136353033303430323031303530306131306130363038326138363438636533643034303330323330326630363039326138363438383666373064303130393034333132323034323062303731303365313430613462386231376262613230316130336163643036396234653431366232613263383066383661383338313435633239373566633131333030613036303832613836343863653364303430333032303434363330343430323230343639306264636637626461663833636466343934396534633035313039656463663334373665303564373261313264376335666538633033303033343464663032323032363764353863393365626233353031333836363062353730373938613064643731313734316262353864626436613138363633353038353431656565393035303030303030303030303030227D \ No newline at end of file diff --git a/public/img/icons-raw/icon-exit-small.svg b/public/img/icons-raw/icon-exit-small.svg deleted file mode 100644 index 90ffb7977..000000000 --- a/public/img/icons-raw/icon-exit-small.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/public/img/icons/icon-exit-small.svg b/public/img/icons/icon-exit-small.svg deleted file mode 100644 index 46c9c7fea..000000000 --- a/public/img/icons/icon-exit-small.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/schema.graphql b/schema.graphql index 9d354b8f8..a678c0a19 100644 --- a/schema.graphql +++ b/schema.graphql @@ -58,6 +58,12 @@ type AuthenticatedUserPayload { errors: [InputValidationError!]! } +type AuthenticatedUserSocialPayload { + authenticatedUser: AuthenticatedUser + errors: [InputValidationError!]! + isNewUser: Boolean +} + type Bible implements Node { abbreviation: String! book(id: ID!): BibleBook! @@ -1637,7 +1643,7 @@ type Mutation { licenseHistoryCommentCreate(input: CatalogHistoryCommentCreateInput!, licenseId: ID!): CatalogHistoryItemPayload! licenseUpdate(input: LicenseUpdateInput!, licenseId: ID!): LicensePayload! login(input: UserLoginInput!): AuthenticatedUserPayload! - loginSocial(input: UserLoginSocialInput!): AuthenticatedUserPayload! + loginSocial(input: UserLoginSocialInput!): AuthenticatedUserSocialPayload! mediaFileDelete(mediaFileId: ID!): SuccessPayload! mediaFileUploadAbort(mediaFileUploadId: ID!): SuccessPayload! mediaFileUploadAssign(mediaFileUploadId: ID!, recordingId: ID!): SuccessPayload! diff --git a/src/components/atoms/activeLink.tsx b/src/components/atoms/activeLink.tsx index d6b1eb8a0..c1987d43f 100644 --- a/src/components/atoms/activeLink.tsx +++ b/src/components/atoms/activeLink.tsx @@ -3,14 +3,12 @@ import { LinkProps } from 'next/link'; import { useRouter } from 'next/router'; import React, { ReactElement } from 'react'; -import { analytics } from '../../lib/analytics'; import Link from './linkWithoutPrefetch'; type ActiveLinkProps = LinkProps & { children: ReactElement; className?: string; activeClassName: string; - linkLabel?: string; }; // SOURCE: https://zaiste.net/programming/reactjs/howtos/create-activelink-nextjs/ @@ -19,7 +17,6 @@ const ActiveLink = ({ children, className, activeClassName, - linkLabel, ...props }: ActiveLinkProps): JSX.Element => { const { asPath } = useRouter(); @@ -34,9 +31,6 @@ const ActiveLink = ({ { - analytics.track('Menu click', { label: linkLabel }); - }} > {children} diff --git a/src/components/atoms/titleLogger.tsx b/src/components/atoms/titleLogger.tsx deleted file mode 100644 index b9a2d8075..000000000 --- a/src/components/atoms/titleLogger.tsx +++ /dev/null @@ -1,31 +0,0 @@ -// components/TitleLogger.tsx -import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; - -function TitleLogger() { - const router = useRouter(); - const [currentTitle, setCurrentTitle] = useState(null); - - useEffect(() => { - const handleRouteChange = () => { - // Access the current title - const newTitle = document.querySelector('title')?.text; - setCurrentTitle(newTitle || null); - }; - - // Listen for route changes - router.events.on('routeChangeComplete', handleRouteChange); - - // Initial title - handleRouteChange(); - - // Remove the event listener on component unmount - return () => { - router.events.off('routeChangeComplete', handleRouteChange); - }; - }, [router.events]); - - return { currentTitle }; -} - -export default TitleLogger; diff --git a/src/components/molecules/buttonDownload.graphql b/src/components/molecules/buttonDownload.graphql index a3dfec980..31c314e36 100644 --- a/src/components/molecules/buttonDownload.graphql +++ b/src/components/molecules/buttonDownload.graphql @@ -1,4 +1,19 @@ fragment buttonDownload on Recording { + id + title + recordingContentType: contentType + speakers: persons(role: SPEAKER) { + ...personLockup + } + sponsor { + title + } + sequence { + title + } + collection { + title + } isDownloadAllowed videoDownloads: videoFiles(allowedContainers: MP4) { url(requestType: DOWNLOAD) diff --git a/src/components/molecules/buttonDownload.tsx b/src/components/molecules/buttonDownload.tsx index 464468388..7107a4cbc 100644 --- a/src/components/molecules/buttonDownload.tsx +++ b/src/components/molecules/buttonDownload.tsx @@ -6,6 +6,7 @@ import { BaseColors } from '~lib/constants'; import { readableBytes } from '~lib/readableBytes'; import iconDownloadAudio from '~public/img/icons/download-audio.svg'; import iconDownloadVedio from '~public/img/icons/download-video.svg'; +import { gtmPushEvent } from '~src/utils/gtm'; import { ButtonDownloadFragment } from './__generated__/buttonDownload'; import styles from './buttonDownload.module.scss'; @@ -99,7 +100,25 @@ export default function ButtonDownload({ {audioDownloads.map(({ url, filesize, bitrate }, index) => (

- + { + gtmPushEvent('download', { + content_type: recording.recordingContentType, + media_type: 'audio', + item_id: recording.id, + title: recording.title, + presenter: recording.speakers + .map((item) => item.name) + .join(';'), + sponsor: recording.sponsor?.title, + conference: recording.collection?.title, + series: recording.sequence?.title, + }); + }} + > {formatLabel( bitrate <= 24 ? 'low' : bitrate <= 48 ? 'medium' : 'high', filesize, @@ -152,7 +171,25 @@ export default function ButtonDownload({ key={index} onClick={handleClose} > - + { + gtmPushEvent('download', { + content_type: recording.recordingContentType, + media_type: 'video', + item_id: recording.id, + title: recording.title, + presenter: recording.speakers + .map((item) => item.name) + .join(';'), + sponsor: recording.sponsor?.title, + conference: recording.collection?.title, + series: recording.sequence?.title, + }); + }} + > {formatLabel( frameSize <= 200000 ? 'low' diff --git a/src/components/molecules/buttonFavorite.tsx b/src/components/molecules/buttonFavorite.tsx index 6c1da02c7..40241dfb8 100644 --- a/src/components/molecules/buttonFavorite.tsx +++ b/src/components/molecules/buttonFavorite.tsx @@ -5,34 +5,38 @@ import { BaseColors } from '~lib/constants'; import IconLike from '~public/img/icons/icon-like.svg'; import IconLikeActive from '~public/img/icons/icon-like-active.svg'; import IconLikeLight from '~public/img/icons/icon-like-light.svg'; +import { gtmPushEvent } from '~src/utils/gtm'; import { analytics } from '../../lib/analytics'; import { isBackgroundColorDark } from './buttonPlay'; +import { ShareContentType } from './buttonShare'; import IconButton from './iconButton'; +type FavoriteContentType = ShareContentType; + type Props = { - favoritedType?: string; - favoritedId?: string | number; - favoritedTitle?: string; isFavorited: boolean; toggleFavorited: () => void; light?: boolean; backgroundColor: BaseColors; className?: string; ref?: Ref; + contentType: FavoriteContentType; + id: string | number | undefined; + title: string; }; const ButtonFavorite = forwardRef( function ButtonFavorite( { - favoritedType, - favoritedId, - favoritedTitle, isFavorited, toggleFavorited, light, backgroundColor, className, + contentType, + id, + title, }: Props, ref, ): JSX.Element { @@ -68,11 +72,16 @@ const ButtonFavorite = forwardRef( e.preventDefault(); e.stopPropagation(); toggleFavorited(); - if (favoritedType) { - analytics.track(isFavorited ? 'Unfavorite' : 'Favorite', { - type: favoritedType, - id: favoritedId, - title: favoritedTitle, + analytics.track(isFavorited ? 'Unfavorite' : 'Favorite', { + type: contentType, + id, + title, + }); + if (!isFavorited) { + gtmPushEvent('favorite', { + content_type: contentType, + item_id: id, + title, }); } }} diff --git a/src/components/molecules/buttonShare.tsx b/src/components/molecules/buttonShare.tsx index b4ba835f6..b4d1e1190 100644 --- a/src/components/molecules/buttonShare.tsx +++ b/src/components/molecules/buttonShare.tsx @@ -5,7 +5,14 @@ import Heading6 from '~components/atoms/heading6'; import { BaseColors } from '~lib/constants'; import ShareIcon from '~public/img/icons/share-alt.svg'; import ShareIconLight from '~public/img/icons/share-alt-light.svg'; +import { + CatalogEntityType, + CollectionContentType, + RecordingContentType, + SequenceContentType, +} from '~src/__generated__/graphql'; import { analytics } from '~src/lib/analytics'; +import { gtmPushEvent } from '~src/utils/gtm'; import { isBackgroundColorDark } from './buttonPlay'; import styles from './buttonShare.module.scss'; @@ -13,6 +20,15 @@ import Dropdown from './dropdown'; import IconButton from './iconButton'; import RssAlternate from './rssAlternate'; +export type ShareContentType = + | RecordingContentType + | SequenceContentType + | CollectionContentType + | typeof CatalogEntityType.Person + | typeof CatalogEntityType.Sponsor + | 'PLAYLIST' + | 'TOPIC'; + type Props = { shareUrl: string; backgroundColor: BaseColors; @@ -20,8 +36,9 @@ type Props = { rssUrl?: string; light?: boolean; triggerClassName?: string; - type?: string; - id?: string | number; + contentType: ShareContentType; + id: string | number | undefined; + title: string; }; export default function ButtonShare({ @@ -32,15 +49,16 @@ export default function ButtonShare({ children, light, triggerClassName, - type, + contentType, id, + title, }: PropsWithChildren): JSX.Element { const intl = useIntl(); const [justCopied, setJustCopied] = useState(false); // FUTURE: update sharing links const facebookLink = `https://facebook.com/share.php?u=${shareUrl}`; - const twitterLink = `https://twitter.com/intent/tweet?url=${shareUrl}`; + const twitterLink = `https://x.com/intent/post?url=${shareUrl}`; const emailLink = `mailto:?body=${shareUrl}${ emailSubject ? `&subject=${encodeURIComponent( @@ -59,12 +77,11 @@ export default function ButtonShare({ const copyLink = shareUrl; const shareTracking = (source: string) => { - if (type) - analytics.track('Share', { - id, - source, - type, - }); + analytics.track('Share', { + id, + source, + type: contentType, + }); }; const onCopyLink = (e: MouseEvent) => { e.preventDefault(); @@ -164,6 +181,15 @@ export default function ButtonShare({ })} className={triggerClassName} {...props} + onClick={(e) => { + // eslint-disable-next-line react/prop-types + props.onClick(e); + gtmPushEvent('share', { + content_type: contentType, + item_id: id, + title, + }); + }} /> )} > diff --git a/src/components/molecules/buttonShareRecording.tsx b/src/components/molecules/buttonShareRecording.tsx index 3560ad6e6..2673934b3 100644 --- a/src/components/molecules/buttonShareRecording.tsx +++ b/src/components/molecules/buttonShareRecording.tsx @@ -4,7 +4,7 @@ import { FormattedMessage, useIntl } from 'react-intl'; import Heading6 from '~components/atoms/heading6'; import { BaseColors } from '~lib/constants'; -import { ButtonShareRecordingFragment } from './__generated__/buttonShareRecording'; +import { PlayerFragment } from './__generated__/player'; import ButtonShare from './buttonShare'; import styles from './buttonShareRecording.module.scss'; @@ -14,14 +14,17 @@ export default function ButtonShareRecording({ shareVideo, disableEmbedCode, }: { - recording: ButtonShareRecordingFragment; + recording: Pick< + PlayerFragment, + 'id' | 'shareUrl' | 'title' | 'speakers' | 'recordingContentType' + >; backgroundColor: BaseColors; shareVideo: boolean; disableEmbedCode?: boolean; }): JSX.Element { const intl = useIntl(); - const { id, shareUrl, title, speakers } = recording; + const { id, shareUrl, title, speakers, recordingContentType } = recording; const embedCode = ``; return ( @@ -39,6 +42,9 @@ export default function ButtonShareRecording({ presenters: speakers.map(({ name }) => name).join(', '), }, ), + contentType: recordingContentType, + id, + title, }} > {!disableEmbedCode && ( diff --git a/src/components/molecules/card/collection.tsx b/src/components/molecules/card/collection.tsx index bb14e8b9b..0cb4e5c52 100644 --- a/src/components/molecules/card/collection.tsx +++ b/src/components/molecules/card/collection.tsx @@ -1,6 +1,5 @@ import clsx from 'clsx'; import Image from 'next/legacy/image'; -import router from 'next/router'; import React from 'react'; import { FormattedMessage } from 'react-intl'; @@ -16,7 +15,6 @@ import { useFormattedDuration } from '~lib/time'; import useHover from '~lib/useHover'; import SuccessIcon from '~public/img/icons/icon-success-light.svg'; import { CollectionContentType } from '~src/__generated__/graphql'; -import { analytics } from '~src/lib/analytics'; import ButtonFavorite from '../buttonFavorite'; import CollectionTypeLockup from '../collectionTypeLockup'; @@ -77,14 +75,6 @@ export default function CardCollection({ isBibleVersion && styles.bibleVersion, (isHovered || isSubHovered) && styles.otherHovered, )} - onClick={() => { - analytics.track('Card click', { - type: contentType, - id, - title, - }); - router.push(canonicalPath); - }} > {heroImage} @@ -151,6 +141,9 @@ export default function CardCollection({ } light className={clsx(styles.like, isFavorited && styles.likeActive)} + contentType={contentType} + id={id} + title={title} /> {sequences?.length || recordings?.length ? ( diff --git a/src/components/molecules/card/person.tsx b/src/components/molecules/card/person.tsx index 9ae6d0886..86cbcceb9 100644 --- a/src/components/molecules/card/person.tsx +++ b/src/components/molecules/card/person.tsx @@ -11,7 +11,6 @@ import Card from '~components/molecules/card'; import { useIsPersonFavorited } from '~lib/api/useIsPersonFavorited'; import { BaseColors } from '~lib/constants'; import { CatalogEntityType } from '~src/__generated__/graphql'; -import { analytics } from '~src/lib/analytics'; import ButtonFavorite from '../buttonFavorite'; import PersonTypeLockup from '../personTypeLockup'; @@ -40,16 +39,7 @@ export default function CardPerson({ return ( - { - analytics.track('Card click', { - type: CatalogEntityType.Person, - id, - title: name, - }); - }} - > +

{!compact && } @@ -100,6 +90,9 @@ export default function CardPerson({ backgroundColor={BaseColors.SMART_PLAYLIST_H} light className={clsx(styles.like, isFavorited && styles.likeActive)} + contentType={CatalogEntityType.Person} + id={id} + title={name} /> )} diff --git a/src/components/molecules/card/sequence.graphql b/src/components/molecules/card/sequence.graphql index f9d9d22fe..ee463eedb 100644 --- a/src/components/molecules/card/sequence.graphql +++ b/src/components/molecules/card/sequence.graphql @@ -6,7 +6,10 @@ fragment cardSequence on Sequence { contentType duration summary - speakers: persons(role: SPEAKER, orderBy: [{ field: NAME, direction: ASC }]) { + sequenceSpeakers: persons( + role: SPEAKER + orderBy: [{ field: NAME, direction: ASC }] + ) { nodes { ...personLockup } diff --git a/src/components/molecules/card/sequence.tsx b/src/components/molecules/card/sequence.tsx index 08f7aa088..26bbdcc75 100644 --- a/src/components/molecules/card/sequence.tsx +++ b/src/components/molecules/card/sequence.tsx @@ -22,7 +22,6 @@ import IconDisclosure from '~public/img/icons/icon-disclosure.svg'; import SuccessIcon from '~public/img/icons/icon-success-light.svg'; import { SequenceContentType } from '~src/__generated__/graphql'; import NameMatcher from '~src/components/atoms/nameMatcher'; -import { analytics } from '~src/lib/analytics'; import ButtonFavorite from '../buttonFavorite'; import PersonLockup from '../personLockup'; @@ -52,6 +51,7 @@ export default function CardSequence({ const isBibleBook = sequence.contentType === SequenceContentType.BibleBook; const { + id, contentType, allRecordings, canonicalPath, @@ -59,9 +59,8 @@ export default function CardSequence({ duration, summary, title, - speakers, + sequenceSpeakers: speakers, sequenceWriters: writers, - id, } = sequence; const { Icon, accentColor, backgroundColor, textColor, label, labelColor } = ( @@ -270,6 +269,9 @@ export default function CardSequence({ backgroundColor={backgroundColor} light className={clsx(styles.like, isFavorited && styles.likeActive)} + contentType={contentType} + id={id} + title={title} />
{recordings?.length ? ( @@ -302,18 +304,7 @@ export default function CardSequence({ return ( - { - analytics.track('Card click', { - type: sequence.contentType, - id, - title, - }); - }} - > - {inner} - + {inner} ); diff --git a/src/components/molecules/card/sermon.spec.tsx b/src/components/molecules/card/sermon.spec.tsx index 4adc16fd3..3a6ed276c 100644 --- a/src/components/molecules/card/sermon.spec.tsx +++ b/src/components/molecules/card/sermon.spec.tsx @@ -18,7 +18,7 @@ const renderComponent = buildRenderer(Page, { recording: { id: 'the_sermon_id', canonicalPath: 'the_sermon_path', - persons: [], + speakers: [], }, }, }); @@ -31,7 +31,7 @@ describe('card sermon', () => { id: 'the_id', title: 'the_title', canonicalPath: 'the_path', - persons: [], + speakers: [], }, }, }); @@ -53,7 +53,7 @@ describe('card sermon', () => { recording: { id: 'the_recording_id', canonicalPath: 'the_sermon_path', - persons: [], + speakers: [], duration: 0, }, }, diff --git a/src/components/molecules/card/sponsor.tsx b/src/components/molecules/card/sponsor.tsx index 3060c7882..028cf6239 100644 --- a/src/components/molecules/card/sponsor.tsx +++ b/src/components/molecules/card/sponsor.tsx @@ -11,7 +11,6 @@ import { useIsSponsorFavorited } from '~lib/api/useIsSponsorFavorited'; import { BaseColors } from '~lib/constants'; import UserPlusIcon from '~public/img/icons/fa-user-plus.svg'; import { CatalogEntityType } from '~src/__generated__/graphql'; -import { analytics } from '~src/lib/analytics'; import ButtonFavorite from '../buttonFavorite'; import TypeLockup from '../typeLockup'; @@ -29,28 +28,19 @@ export default function CardSponsor({ const { isFavorited, toggleFavorited } = useIsSponsorFavorited(sponsor.id); const { + id, canonicalPath, image, title, collections, sequences, recordings, - id, } = sponsor; return ( - { - analytics.track('Card click', { - type: CatalogEntityType.Sponsor, - id, - title, - }); - }} - > + ); diff --git a/src/components/molecules/navItem.tsx b/src/components/molecules/navItem.tsx index e51853a65..036bf7aa3 100644 --- a/src/components/molecules/navItem.tsx +++ b/src/components/molecules/navItem.tsx @@ -6,8 +6,6 @@ import styles from '~components/organisms/navigation.module.scss'; import { INavigationItem } from '~lib/useNavigationItems'; import IconDisclosure from '~public/img/icons/icon-disclosure-light-small.svg'; -import { analytics } from '../../lib/analytics'; - export default function NavItem({ item, setSubmenu, @@ -31,7 +29,6 @@ export default function NavItem({ href={href} className={styles.navLink} activeClassName={styles.active} - linkLabel={label} > {inner} @@ -39,7 +36,6 @@ export default function NavItem({ { - analytics.track('Menu click', { label }); setSubmenu(key); }} > diff --git a/src/components/molecules/player.graphql b/src/components/molecules/player.graphql index 213a1f8c8..5ecf40c54 100644 --- a/src/components/molecules/player.graphql +++ b/src/components/molecules/player.graphql @@ -1,6 +1,4 @@ fragment player on Recording { - id - title ...andMiniplayer ...buttonDownload ...buttonShareRecording diff --git a/src/components/molecules/recordingButtonFavorite.spec.tsx b/src/components/molecules/recordingButtonFavorite.spec.tsx deleted file mode 100644 index ee56817a0..000000000 --- a/src/components/molecules/recordingButtonFavorite.spec.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import Cookie from 'js-cookie'; -import { __loadRouter } from 'next/router'; -import React from 'react'; - -import RecordingButtonFavorite from '~components/molecules/recordingButtonFavorite'; -import { recordingIsFavorited } from '~lib/api/recordingIsFavorited'; -import { setRecordingFavorited } from '~lib/api/setRecordingFavorited'; -import { BaseColors } from '~lib/constants'; -import loadControlledPromise from '~lib/test/loadControlledPromise'; -import renderWithProviders from '~lib/test/renderWithProviders'; - -jest.mock('~lib/api/recordingIsFavorited'); -jest.mock('~lib/api/setRecordingFavorited'); -jest.mock('js-cookie'); - -const renderComponent = async () => { - const result = await renderWithProviders( - , - undefined, - ); - const button = - result.queryByLabelText('Favorite') || - result.queryByLabelText('Unfavorite'); - - if (!button) { - throw new Error("Can't find button"); - } - - return { - ...result, - button, - }; -}; - -const mockRecordingIsFavorited = recordingIsFavorited as jest.Mock; -const mockSetRecordingFavorited = setRecordingFavorited as jest.Mock; - -describe('recording favorite button', () => { - beforeEach(() => { - __loadRouter({ - pathname: '/en/discover', - }); - Cookie.get = jest.fn().mockReturnValue({ avSession: 'abc123' }); - mockRecordingIsFavorited.mockResolvedValue(false); - }); - - it('shows favorite button', async () => { - const { getByLabelText } = await renderComponent(); - - expect(getByLabelText('Favorite')).toBeInTheDocument(); - }); - - it('shows unfavorite button', async () => { - mockRecordingIsFavorited.mockResolvedValue(true); - - const { findByLabelText } = await renderComponent(); - - await expect(findByLabelText('Unfavorite')).resolves.toBeInTheDocument(); - }); - - it('gets favorited status', async () => { - await renderComponent(); - - expect(recordingIsFavorited).toBeCalled(); - }); - - it('triggers mutation', async () => { - mockSetRecordingFavorited.mockResolvedValue(true); - - const { button } = await renderComponent(); - - await userEvent.click(button); - - await waitFor(() => - expect(setRecordingFavorited).toBeCalledWith('-1', true), - ); - }); - - it('updates button when clicked', async () => { - const { findByLabelText, button } = await renderComponent(); - - mockRecordingIsFavorited.mockResolvedValue(true); - mockSetRecordingFavorited.mockResolvedValue(true); - - await userEvent.click(button); - - await expect(findByLabelText('Unfavorite')).resolves.toBeInTheDocument(); - }); - - it('rolls back state if API fails', async () => { - const { button } = await renderComponent(); - - const { reject } = loadControlledPromise(mockSetRecordingFavorited); - - await userEvent.click(button); - - expect(await screen.findByLabelText('Unfavorite')).toBeInTheDocument(); - - reject(); - - expect(await screen.findByLabelText('Favorite')).toBeInTheDocument(); - }); - - it('does not roll back state if API succeeds', async () => { - const isFavoritedSpy = mockRecordingIsFavorited; - mockSetRecordingFavorited.mockResolvedValue(true); - - isFavoritedSpy.mockResolvedValue(false); - - const { button, findByLabelText } = await renderComponent(); - - isFavoritedSpy.mockResolvedValue(true); - - await userEvent.click(button); - - await expect(findByLabelText('Unfavorite')).resolves.toBeInTheDocument(); - await expect(findByLabelText('Favorite')).rejects.toThrow(); - }); - - it('sets aria-pressed=false', async () => { - const { getByLabelText } = await renderComponent(); - - expect(getByLabelText('Favorite')).not.toHaveAttribute( - 'aria-pressed', - 'true', - ); - }); - - it('sets aria-pressed=true', async () => { - mockRecordingIsFavorited.mockResolvedValue(true); - - const { findByLabelText } = await renderComponent(); - - await expect(findByLabelText('Unfavorite')).resolves.toHaveAttribute( - 'aria-pressed', - 'true', - ); - }); - - it('uses favorite icon', async () => { - const { getByTestId } = await renderComponent(); - - expect(getByTestId('favorite-icon')).toBeInTheDocument(); - }); - - it('uses unfavorite icon', async () => { - mockRecordingIsFavorited.mockResolvedValue(true); - - await renderComponent(); - - await waitFor(() => { - expect(screen.getByTestId('unfavorite-icon')).toBeInTheDocument(); - }); - }); -}); diff --git a/src/components/molecules/recordingButtonFavorite.tsx b/src/components/molecules/recordingButtonFavorite.tsx deleted file mode 100644 index 58cfd4a14..000000000 --- a/src/components/molecules/recordingButtonFavorite.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import { useIsRecordingFavorited } from '~lib/api/useIsRecordingFavorited'; -import { BaseColors } from '~lib/constants'; -import { Scalars } from '~src/__generated__/graphql'; - -import ButtonFavorite from './buttonFavorite'; - -export default function RecordingButtonFavorite({ - id, - title, - sequenceId, - ...props -}: { - id: Scalars['ID']['output']; - title?: string; - sequenceId?: Scalars['ID']['output']; - backgroundColor: BaseColors; - light?: boolean; - className?: string; -}): JSX.Element { - const { isFavorited, toggleFavorited } = useIsRecordingFavorited( - id, - sequenceId, - ); - - return ( - - ); -} diff --git a/src/components/molecules/searchBar.module.scss b/src/components/molecules/searchBar.module.scss index b76430110..573b25dc6 100644 --- a/src/components/molecules/searchBar.module.scss +++ b/src/components/molecules/searchBar.module.scss @@ -92,6 +92,9 @@ letter-spacing: 0em; text-align: left; margin-left: 28px; + @media (max-width: $breakpoint-sm) { + display: none; + } } .filters { diff --git a/src/components/molecules/searchBar.tsx b/src/components/molecules/searchBar.tsx index 1efa652a4..55ee07966 100644 --- a/src/components/molecules/searchBar.tsx +++ b/src/components/molecules/searchBar.tsx @@ -79,7 +79,7 @@ export default function SearchBar({ > { + onSuccess: async (response, variables) => { const errors = response?.loginSocial.errors || []; const token = response?.loginSocial.authenticatedUser?.sessionToken; @@ -50,6 +51,17 @@ export default function SocialLogin({ email: user?.email, source: 'Login', }); + if (response?.loginSocial.isNewUser) { + gtmPushEvent('sign_up', { + sign_up_method: variables?.socialName, + user_id: user?.id, + }); + } else { + gtmPushEvent('sign_in', { + sign_in_method: variables?.socialName, + user_id: user?.id, + }); + } onSuccess ? onSuccess() : await queryClient.invalidateQueries(); } else if (!didUnmount.current) { setErrors(errors.map((e) => e.message)); diff --git a/src/components/molecules/teaseRecording.graphql b/src/components/molecules/teaseRecording.graphql index eec749732..e1e7d4cf8 100644 --- a/src/components/molecules/teaseRecording.graphql +++ b/src/components/molecules/teaseRecording.graphql @@ -1,10 +1,5 @@ fragment teaseRecording on Recording { ...andMiniplayer - recordingContentType: contentType - canonicalPath(useFuturePath: true) - persons(role: SPEAKER) { - ...personLockup - } sequenceIndex sequence { id diff --git a/src/components/molecules/teaseRecording.tsx b/src/components/molecules/teaseRecording.tsx index 3d5def0fa..de7a4f6ec 100644 --- a/src/components/molecules/teaseRecording.tsx +++ b/src/components/molecules/teaseRecording.tsx @@ -8,7 +8,6 @@ import Link from '~components/atoms/linkWithoutPrefetch'; import { AndMiniplayerFragment } from '~components/templates/__generated__/andMiniplayer'; import { BaseColors } from '~lib/constants'; -import { analytics } from '../../lib/analytics'; import { TeaseRecordingFragment } from './__generated__/teaseRecording'; import ButtonAddToPlaylist from './buttonAddToPlaylist'; import PlayButton from './buttonPlayCircle'; @@ -78,7 +77,7 @@ export default function TeaseRecording({ {!hidePresenters && (
- {recording.persons.map((p) => ( + {recording.speakers.map((p) => ( { - analytics.track('Card click', { - type: recording.recordingContentType, - id: recording.id, - title: recording.title, - }); router.push(recording.canonicalPath); }} > @@ -133,13 +127,6 @@ export default function TeaseRecording({ unpadded && styles.unpadded, fullBleed && styles.fullBleed, )} - onClick={() => { - analytics.track('Card click', { - type: recording.recordingContentType, - id: recording.id, - title: recording.title, - }); - }} > {inner} diff --git a/src/components/organisms/drawer.tsx b/src/components/organisms/drawer.tsx index e3a2a771d..ac5cc510c 100644 --- a/src/components/organisms/drawer.tsx +++ b/src/components/organisms/drawer.tsx @@ -10,13 +10,9 @@ import styles from './drawer.module.scss'; export default function Drawer({ showingMenu, onExit, - onSearchChange, - searchTerm, }: { showingMenu: boolean; onExit: () => void; - onSearchChange: (term: string | undefined) => void; - searchTerm?: string; }): JSX.Element { useEffect(() => { Router.events.on('routeChangeStart', onExit); @@ -34,11 +30,7 @@ export default function Drawer({
- +
); diff --git a/src/components/organisms/mobileHeader.module.scss b/src/components/organisms/mobileHeader.module.scss index 86ea0d0c1..8d744b09d 100644 --- a/src/components/organisms/mobileHeader.module.scss +++ b/src/components/organisms/mobileHeader.module.scss @@ -70,45 +70,6 @@ border: none; } -.search { - display: none; - background: $ts-cream; - padding-top: 8px; - - @include hpad(); - - .searchInput { - background: $ts-white; - border-bottom: none; - border-radius: 4px; - padding: 4px 12px 4px 8px; - height: 32px; - - > svg { - color: $ts-red; - } - - input, - input::placeholder { - font-size: 16px; - line-height: 24px; - font-weight: 400; - } - } - - > button { - margin-left: 8px; - } -} - -.searchActive { - display: flex; -} - -.searchFilters { - padding-top: 8px; -} - @media (min-width: $breakpoint-lg) { .base { display: none; diff --git a/src/components/organisms/mobileHeader.tsx b/src/components/organisms/mobileHeader.tsx index 9c7c6bbf3..b099b51e2 100644 --- a/src/components/organisms/mobileHeader.tsx +++ b/src/components/organisms/mobileHeader.tsx @@ -6,37 +6,25 @@ import { FormattedMessage, useIntl } from 'react-intl'; import Button from '~components/molecules/button'; import ButtonPlayback from '~components/molecules/buttonPlayback'; import Mininav from '~components/molecules/mininav'; -import SearchBar from '~components/molecules/searchBar'; import Header from '~components/organisms/header'; import { PlaybackContext } from '~components/templates/andPlaybackContext'; import root from '~lib/routes'; import useLanguageRoute from '~lib/useLanguageRoute'; import { useNavigationItems } from '~lib/useNavigationItems'; -import IconExitSmall from '~public/img/icons/icon-exit-small.svg'; import MoreIcon from '~public/img/icons/icon-more.svg'; -import { analytics } from '../../lib/analytics'; import OpenAppButton from '../molecules/openAppButton'; import styles from './mobileHeader.module.scss'; import useScrollDirection, { SCROLL_DIRECTIONS, } from './mobileHeader.useScrollDirection'; -import { EntityFilterId } from './searchResults.filters'; export default function MobileHeader({ setShowingMenu, scrollRef, - term, - onTermChange, - entityType, - onEntityTypeChange, }: { setShowingMenu: (showingMenu: boolean) => void; scrollRef: React.RefObject; - term?: string; - onTermChange: (term: string | undefined) => void; - entityType: EntityFilterId; - onEntityTypeChange: (entityType: EntityFilterId) => void; }): JSX.Element { const intl = useIntl(); const { asPath } = useRouter(); @@ -59,9 +47,6 @@ export default function MobileHeader({