8889841cPK[cVcomponents/GreenButton.jsnu[import React from 'react'; import cx from 'classnames'; import styles from './GreenButton.module.css'; export default function GreenButton({as: Element = 'button', text, className, shadow = false, ...props}) { const classes = cx(styles.button, shadow && styles.shadow, className); if (Element === 'input') { return ; } return ( {text} ); } PK[QQ!components/GreenButton.module.cssnu[.button { appearance: none; display: block; cursor: pointer; padding: 0.888em; border-radius: 9999px; border-width: 0.125rem; border-style: solid; border-color: #66bb6a; background-color: #66bb6a; color: #fff; font-weight: 700; font-size: 1.125rem; text-align: center; text-decoration: none; line-height: 1; letter-spacing: -0.0278em; transition-duration: 200ms; transition-property: filter, color, background-color, text-shadow, box-shadow; transition-timing-function: ease; } .shadow { box-shadow: 0 2px 10px 0 rgba(105, 184, 107, 0.6); } .button:hover, .button:active, .button:focus { text-shadow: 0 0 0.125em rgba(0, 0, 0, 0.3); filter: brightness(115%); color: #fff; } .button:focus { box-shadow: 0 0 0.0625em 0.25em rgba(102, 187, 106, 0.4); } PK[^J J !hooks/useFreeAddonSubscription.jsnu[import {useState, useCallback} from 'react'; /** * Handles making a request to add a user to the Free Addon email subscription. It returns whether the request worked, * failed, and the callback to trigger it all. * * @param {String} reason "rejected" or "subscribed" * @returns {boolean} Whether the request was successful. */ async function markSubscriptionComplete(reason) { const response = await fetch(giveFreeAddonModal.apiRoot, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-WP-Nonce': giveFreeAddonModal.nonce, }, body: JSON.stringify({reason}), }); return response.ok; } export default function useFreeAddonSubscription() { const [userSubscribed, setUserSubscribed] = useState(false); const [hasSubmissionError, setHasSubmissionError] = useState(false); const handleSubscribe = useCallback( /** * @param {String} firstName * @param {String} email * @param {String} siteUrl * @param {String} siteName * @returns {Promise} */ async (firstName, email, siteUrl, siteName) => { try { const response = await fetch('https://connect.givewp.com/activecampaign/subscribe/free-add-on', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ first_name: firstName, email, website_url: siteUrl, website_name: siteName, }), }); if (response.ok) { setUserSubscribed(true); markSubscriptionComplete('subscribed'); } else { setHasSubmissionError(true); } } catch (error) { setHasSubmissionError(true); } }, [setUserSubscribed, setHasSubmissionError] ); return { userSubscribed, hasSubscriptionError: hasSubmissionError, subscribeUser: handleSubscribe, rejectOffer: () => markSubscriptionComplete('rejected'), }; } PK[ЖP  hooks/useRecommendations.tsnu[import {useCallback, useState} from 'react'; import dismissRecommendation from '@givewp/promotions/requests/dismissRecommendation'; type EnumValues = | 'givewp_donations_recurring_recommendation_dismissed' | 'givewp_donations_fee_recovery_recommendation_dismissed' | 'givewp_donations_designated_funds_recommendation_dismissed' | 'givewp_reports_recurring_recommendation_dismissed' | 'givewp_reports_fee_recovery_recommendation_dismissed' | 'givewp_donors_fee_recovery_recommendation_dismissed' | 'givewp_reports_fee_recovery_recommendation_dismissed'; export interface RecommendedProductData { enum: EnumValues; documentationPage: string; message: string; innerHtml: string; } /** * @since 2.27.1 */ export function useRecommendations(apiSettings, options) { const [dismissedRecommendations, setDismissedRecommendations] = useState( apiSettings.dismissedRecommendations ); const getRandomRecommendation = useCallback((): RecommendedProductData | null => { const availableOptions = options.filter((option) => !dismissedRecommendations.includes(option.enum)); if (availableOptions.length === 0) { return null; } const randomIndex = Math.floor(Math.random() * availableOptions.length); return availableOptions[randomIndex]; }, [dismissedRecommendations]); const getRecommendation = useCallback((): RecommendedProductData | null => { const availableOptions = options.filter((option) => !dismissedRecommendations.includes(option.enum)); if (availableOptions.length === 0) { return null; } return availableOptions[0]; }, [dismissedRecommendations]); const removeRecommendation = async (data: {option: EnumValues}): Promise => { setDismissedRecommendations((prev) => [...prev, data.option]); await dismissRecommendation(data.option, apiSettings.apiNonce); }; return {getRecommendation, getRandomRecommendation, removeRecommendation}; } PK[^!requests/dismissRecommendation.tsnu[/** * * @since 2.27.1 * */ export default async function dismissRecommendation(option: string, nonce: string) { const url = '/wp-json/give-api/v2/admin/recommended-options'; await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce, }, body: JSON.stringify({ option }), }); } PK[cVcomponents/GreenButton.jsnu[PK[QQ!^components/GreenButton.module.cssnu[PK[^J J !hooks/useFreeAddonSubscription.jsnu[PK[ЖP  hooks/useRecommendations.tsnu[PK[^!requests/dismissRecommendation.tsnu[PK