AW-483-484-485-fix-bugs

This commit is contained in:
Daniil Chemerkin 2025-09-12 15:46:08 +00:00
parent 4b7332f4d5
commit 5cc17824f3
16 changed files with 385 additions and 92 deletions

View File

@ -664,6 +664,12 @@
"title": "Bought today: <count>", "title": "Bought today: <count>",
"description": "<count> people are buying now:" "description": "<count> people are buying now:"
} }
},
"price-descriptions": {
"1": "Basic",
"2": "Standard",
"3": "Popular",
"4": "Premium"
} }
}, },
"/scan-hand": { "/scan-hand": {

View File

@ -7,6 +7,20 @@
"day": "Day", "day": "Day",
"year": "Year", "year": "Year",
"month": "Month", "month": "Month",
"months": {
"january": "January",
"february": "February",
"march": "March",
"april": "April",
"may": "May",
"june": "June",
"july": "July",
"august": "August",
"september": "September",
"october": "October",
"november": "November",
"december": "December"
},
"aura_paywall_redesign_main": { "aura_paywall_redesign_main": {
"text_0": "We've helped millions of people to have happier lives and better relationships, and we want to help you too.", "text_0": "We've helped millions of people to have happier lives and better relationships, and we want to help you too.",
"text_0_color": "millions", "text_0_color": "millions",

View File

@ -14,6 +14,7 @@ import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User"; import { ESourceAuthorization } from "@/api/resources/User";
import { usePreloadImages } from "@/hooks/preload/images"; import { usePreloadImages } from "@/hooks/preload/images";
import { getZodiacSignByDate, ZODIACS } from "@/services/zodiac-sign"; import { getZodiacSignByDate, ZODIACS } from "@/services/zodiac-sign";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
function Birthdate() { function Birthdate() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@ -26,14 +27,19 @@ function Birthdate() {
const { gender } = useSelector(selectors.selectQuestionnaire); const { gender } = useSelector(selectors.selectQuestionnaire);
const zodiacSign = getZodiacSignByDate(birthdate); const zodiacSign = getZodiacSignByDate(birthdate);
const { variant: dateMonth = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityDateMonth,
});
usePreloadImages( usePreloadImages(
!!zodiacSign?.length ? zodiacSign?.length
[ ? [
`/zodiac-signs/${gender?.toLowerCase()}/${zodiacSign?.toLowerCase()}.svg` `/zodiac-signs/${gender?.toLowerCase()}/${zodiacSign?.toLowerCase()}.svg`,
] : ]
ZODIACS.map( : ZODIACS.map(
(zodiac) => `/zodiac-signs/${gender?.toLowerCase()}/${zodiac?.toLowerCase()}.svg` (zodiac) =>
) `/zodiac-signs/${gender?.toLowerCase()}/${zodiac?.toLowerCase()}.svg`
)
); );
const handleValid = (_birthdate: string) => { const handleValid = (_birthdate: string) => {
@ -82,6 +88,7 @@ function Birthdate() {
onValid={handleValid} onValid={handleValid}
onInvalid={() => setIsDisabled(true)} onInvalid={() => setIsDisabled(true)}
inputClassName="date-picker-input" inputClassName="date-picker-input"
monthsDisplay={dateMonth === "v1" ? "name" : "number"}
/> />
<Button <Button
className={styles.button} className={styles.button}

View File

@ -13,6 +13,7 @@ import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User"; import { ESourceAuthorization } from "@/api/resources/User";
import { usePreloadImages } from "@/hooks/preload/images"; import { usePreloadImages } from "@/hooks/preload/images";
import { getZodiacSignByDate, ZODIACS } from "@/services/zodiac-sign"; import { getZodiacSignByDate, ZODIACS } from "@/services/zodiac-sign";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
function BirthdatePartner() { function BirthdatePartner() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@ -24,6 +25,10 @@ function BirthdatePartner() {
const [isDisabled, setIsDisabled] = useState(true); const [isDisabled, setIsDisabled] = useState(true);
const zodiacSign = getZodiacSignByDate(birthdate); const zodiacSign = getZodiacSignByDate(birthdate);
const { variant: dateMonth = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityDateMonth,
});
usePreloadImages( usePreloadImages(
!!zodiacSign?.length ? !!zodiacSign?.length ?
[ [
@ -64,6 +69,7 @@ function BirthdatePartner() {
onValid={handleValid} onValid={handleValid}
onInvalid={() => setIsDisabled(true)} onInvalid={() => setIsDisabled(true)}
inputClassName="date-picker-input" inputClassName="date-picker-input"
monthsDisplay={dateMonth === "v1" ? "name" : "number"}
/> />
<Button <Button
className={styles.button} className={styles.button}

View File

@ -11,6 +11,7 @@ import { useTranslations } from "@/hooks/translations";
import { ELocalesPlacement } from "@/locales"; import { ELocalesPlacement } from "@/locales";
import { useSession } from "@/hooks/session/useSession"; import { useSession } from "@/hooks/session/useSession";
import { ESourceAuthorization } from "@/api/resources/User"; import { ESourceAuthorization } from "@/api/resources/User";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
function DateEvent() { function DateEvent() {
const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2);
@ -23,6 +24,10 @@ function DateEvent() {
const [dateEvent, setDateEvent] = useState(dateEventFromStore); const [dateEvent, setDateEvent] = useState(dateEventFromStore);
const [isDisabled, setIsDisabled] = useState(true); const [isDisabled, setIsDisabled] = useState(true);
const { variant: dateMonth = "v0" } = useUnleash({
flag: EUnleashFlags.v2CompatibilityDateMonth,
});
const handleValid = (_birthdate: string) => { const handleValid = (_birthdate: string) => {
setDateEvent(_birthdate); setDateEvent(_birthdate);
setIsDisabled(_birthdate === ""); setIsDisabled(_birthdate === "");
@ -54,6 +59,7 @@ function DateEvent() {
onInvalid={() => setIsDisabled(true)} onInvalid={() => setIsDisabled(true)}
inputClassName="date-picker-input" inputClassName="date-picker-input"
differenceOfMaximumAndCurrentYear={0} differenceOfMaximumAndCurrentYear={0}
monthsDisplay={dateMonth === "v1" ? "name" : "number"}
/> />
<Button <Button
className={styles.button} className={styles.button}

View File

@ -116,7 +116,7 @@ function TrialChoice() {
}; };
const handleNext = () => { const handleNext = () => {
if (isDisabled && trialButtonVariant === "v1") { if (isDisabled && ["v1", "v2", "v3", "v4"].includes(trialButtonVariant)) {
setIsDisabledButtonClicked(true); setIsDisabledButtonClicked(true);
bottomRef.current?.scrollIntoView({ bottomRef.current?.scrollIntoView({
@ -203,37 +203,48 @@ function TrialChoice() {
<div className={`${styles["price-container"]}`}> <div className={`${styles["price-container"]}`}>
<div <div
className={`${styles.priceListContainer} ${ className={`${styles.priceListContainer} ${
isDisabledButtonClicked && isDisabled isDisabledButtonClicked &&
isDisabled &&
["v1", "v2"].includes(trialButtonVariant)
? styles.priceListContainerDisabled ? styles.priceListContainerDisabled
: "" : ""
}`} }`}
> >
{isDisabledButtonClicked && isDisabled && ( {isDisabledButtonClicked &&
<div className={styles.priceListContainerDisabledText}> isDisabled &&
<svg ["v1", "v2"].includes(trialButtonVariant) && (
width="16" <div className={styles.priceListContainerDisabledText}>
height="16" <svg
viewBox="0 0 16 16" width="16"
fill="none" height="16"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
> fill="none"
<rect width="16" height="16" rx="8" fill="#EF4444" /> xmlns="http://www.w3.org/2000/svg"
<path >
d="M8.75 3C8.75 2.58516 8.41484 2.25 8 2.25C7.58516 2.25 7.25 2.58516 7.25 3V9C7.25 9.41484 7.58516 9.75 8 9.75C8.41484 9.75 8.75 9.41484 8.75 9V3ZM8 12.75C8.24864 12.75 8.4871 12.6512 8.66291 12.4754C8.83873 12.2996 8.9375 12.0611 8.9375 11.8125C8.9375 11.5639 8.83873 11.3254 8.66291 11.1496C8.4871 10.9738 8.24864 10.875 8 10.875C7.75136 10.875 7.5129 10.9738 7.33709 11.1496C7.16127 11.3254 7.0625 11.5639 7.0625 11.8125C7.0625 12.0611 7.16127 12.2996 7.33709 12.4754C7.5129 12.6512 7.75136 12.75 8 12.75Z" <rect width="16" height="16" rx="8" fill="#EF4444" />
fill="white" <path
/> d="M8.75 3C8.75 2.58516 8.41484 2.25 8 2.25C7.58516 2.25 7.25 2.58516 7.25 3V9C7.25 9.41484 7.58516 9.75 8 9.75C8.41484 9.75 8.75 9.41484 8.75 9V3ZM8 12.75C8.24864 12.75 8.4871 12.6512 8.66291 12.4754C8.83873 12.2996 8.9375 12.0611 8.9375 11.8125C8.9375 11.5639 8.83873 11.3254 8.66291 11.1496C8.4871 10.9738 8.24864 10.875 8 10.875C7.75136 10.875 7.5129 10.9738 7.33709 11.1496C7.16127 11.3254 7.0625 11.5639 7.0625 11.8125C7.0625 12.0611 7.16127 12.2996 7.33709 12.4754C7.5129 12.6512 7.75136 12.75 8 12.75Z"
</svg> fill="white"
/>
</svg>
{translate("/trial-choice.please-select")} {translate("/trial-choice.please-select")}
</div> </div>
)} )}
<PriceList <PriceList
products={products} products={products}
activeItem={selectedPrice} activeItem={selectedPrice}
classNameItem={styles["price-item"]} classNameItem={`${styles["price-item"]} ${
styles[trialButtonVariant]
} ${
isDisabledButtonClicked && isDisabled
? styles.priceItemDisabled
: ""
}`}
classNameItemActive={`${styles["price-item-active"]}`} classNameItemActive={`${styles["price-item-active"]}`}
classNamePricesContainer={styles["prices-container"]} classNamePricesContainer={styles["prices-container"]}
classNameDescription={styles["price-item-description"]}
currency={currency} currency={currency}
showArrow={true} showArrow={true}
productWidthArrow={products[products.length - 1]} productWidthArrow={products[products.length - 1]}
@ -253,6 +264,17 @@ function TrialChoice() {
</svg> </svg>
} }
click={handlePriceItem} click={handlePriceItem}
displayMode={["v2", "v4"].includes(trialButtonVariant) ? "grid" : "row"}
pricesDescription={
["v2", "v4"].includes(trialButtonVariant)
? [
translate("/trial-choice.price-descriptions.1"),
translate("/trial-choice.price-descriptions.2"),
translate("/trial-choice.price-descriptions.3"),
translate("/trial-choice.price-descriptions.4"),
]
: []
}
/> />
</div> </div>
<p className={styles["auxiliary-text"]}> <p className={styles["auxiliary-text"]}>
@ -268,13 +290,17 @@ function TrialChoice() {
<Button <Button
className={`${styles.button} ${ className={`${styles.button} ${
trialButtonVariant === "v1" ? styles["button-v1"] : "" ["v1", "v2", "v3", "v4"].includes(trialButtonVariant)
? styles["button-v1"]
: ""
} ${ } ${
isDisabled && trialButtonVariant === "v1" isDisabled && ["v1", "v2", "v3", "v4"].includes(trialButtonVariant)
? styles["button-v1-disabled"] ? styles["button-v1-disabled"]
: "" : ""
}`} }`}
disabled={isDisabled && trialButtonVariant !== "v1"} disabled={
isDisabled && !["v1", "v2", "v3", "v4"].includes(trialButtonVariant)
}
onClick={handleNext} onClick={handleNext}
> >
{translate("next")} {translate("next")}

View File

@ -65,6 +65,54 @@
color: #fb6c6c; color: #fb6c6c;
border-color: #fb6c6c; border-color: #fb6c6c;
} }
&.v1,
&.v3 {
border: 1px solid #9ca3af;
&.price-item-active {
background: linear-gradient(90deg, #5393de 0%, #3a70b2 100%);
color: #fff !important;
border: none !important;
}
&:last-child {
border-width: 3px;
}
}
&.v2,
&.v4 {
font-weight: 700;
border: 2px solid #d1d5db;
border-radius: 12px;
&.price-item-active {
background: linear-gradient(90deg, #5393de 0%, #3a70b2 100%);
color: #fff !important;
border: 2px solid #3a70b2;
& > .price-item-description {
color: #fff;
}
}
&:last-child {
border-width: 4px;
}
}
&.v3,
&.v4 {
&.priceItemDisabled {
color: #fb6c6c;
border-color: #fb6c6c;
& > .price-item-description {
color: #fb6c6c;
}
}
}
} }
:global(.dark-theme) .price-item { :global(.dark-theme) .price-item {
@ -79,6 +127,52 @@
color: #fb6c6c; color: #fb6c6c;
border-color: #fb6c6c; border-color: #fb6c6c;
} }
&.v1,
&.v3 {
border: 1px solid #9ca3af;
&.price-item-active {
background: linear-gradient(90deg, #5393de 0%, #3a70b2 100%);
color: #fff !important;
border: none !important;
}
&:last-child {
border-width: 3px;
}
}
&.v2,
&.v4 {
border: 2px solid #d1d5db;
&.price-item-active {
background: linear-gradient(90deg, #5393de 0%, #3a70b2 100%);
color: #fff !important;
border: 2px solid #3a70b2;
& > .price-item-description {
color: #fff;
}
}
&:last-child {
border-width: 4px;
}
}
&.v3,
&.v4 {
&.priceItemDisabled {
color: #fb6c6c;
border-color: #fb6c6c;
& > .price-item-description {
color: #fb6c6c;
}
}
}
} }
.price-container { .price-container {
@ -118,15 +212,11 @@
} }
& .price-item { & .price-item {
border: 1px solid rgba(156, 163, 175, 1); // border: 1px solid rgba(156, 163, 175, 1);
color: #000; color: #000;
background-color: #fff; background-color: #fff;
box-shadow: 0px 4px 6px 0px rgba(0, 0, 0, 0.1), box-shadow: 0px 4px 6px 0px rgba(0, 0, 0, 0.1),
0px 2px 4px 0px rgba(0, 0, 0, 0.1); 0px 2px 4px 0px rgba(0, 0, 0, 0.1);
&:last-child {
border-width: 3px;
}
} }
} }
} }

View File

@ -1,4 +1,5 @@
import { FormField } from "@/types"; import { FormField } from "@/types";
import { MonthOption } from "@/utils/monthNames";
type DatePartValue = string | undefined; type DatePartValue = string | undefined;
@ -6,7 +7,7 @@ type DateInputProps = Omit<
FormField<DatePartValue>, FormField<DatePartValue>,
"onValid" | "onInvalid" "onValid" | "onInvalid"
> & { > & {
values: number[] | string[]; values: (number | string | MonthOption)[];
onChange: (part: string) => void; onChange: (part: string) => void;
}; };
@ -21,8 +22,8 @@ function DateInput(props: DateInputProps): JSX.Element {
onChange, onChange,
} = props; } = props;
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const datePart = e.target.value ? parseInt(e.target.value, 10) : 0; const selectedValue = e.target.value;
onChange(String(datePart)); onChange(selectedValue);
}; };
return ( return (
<div className={`date-picker__field ${inputClassName ?? ""}`}> <div className={`date-picker__field ${inputClassName ?? ""}`}>
@ -37,11 +38,15 @@ function DateInput(props: DateInputProps): JSX.Element {
<option value="" hidden> <option value="" hidden>
{placeholder} {placeholder}
</option> </option>
{values.map((_value, index) => ( {values.map((_value, index) => {
<option key={`${_value}_${index}`} value={_value}> const optionValue = typeof _value === 'object' ? _value.value : _value;
{_value} const optionLabel = typeof _value === 'object' ? _value.label : _value;
</option> return (
))} <option key={`${optionValue}_${index}`} value={optionValue}>
{optionLabel}
</option>
);
})}
</select> </select>
</div> </div>
); );

View File

@ -7,14 +7,24 @@ import { stringify, getCurrentYear } from "./utils";
import { IDate, getDateAsString } from "@/services/date"; import { IDate, getDateAsString } from "@/services/date";
import { ELocalesPlacement, language } from "@/locales"; import { ELocalesPlacement, language } from "@/locales";
import { getDateInputLocaleFormat } from "@/locales/localFormats"; import { getDateInputLocaleFormat } from "@/locales/localFormats";
import { getMonthOptions } from "@/utils/monthNames";
export function DatePicker( export function DatePicker(
props: FormField<Date | IDate | string> & { props: FormField<Date | IDate | string> & {
differenceOfMaximumAndCurrentYear?: number; differenceOfMaximumAndCurrentYear?: number;
monthsDisplay?: "number" | "name";
} }
): JSX.Element { ): JSX.Element {
const { translate } = useTranslations(ELocalesPlacement.V1); const { translate } = useTranslations(ELocalesPlacement.V1);
const { name, value, inputClassName, differenceOfMaximumAndCurrentYear = 11, onValid, onInvalid } = props; const {
name,
value,
inputClassName,
differenceOfMaximumAndCurrentYear = 11,
onValid,
onInvalid,
monthsDisplay = "number",
} = props;
const date = getDateAsString(value); const date = getDateAsString(value);
const [initYear, initMonth, initDay] = date.split("-"); const [initYear, initMonth, initDay] = date.split("-");
const [year, setYear] = useState(initYear); const [year, setYear] = useState(initYear);
@ -31,12 +41,15 @@ export function DatePicker(
return Array.from({ length: 66 }, (_, index) => { return Array.from({ length: 66 }, (_, index) => {
return currentYear - differenceOfMaximumAndCurrentYear - index; return currentYear - differenceOfMaximumAndCurrentYear - index;
}); });
}, []); }, [differenceOfMaximumAndCurrentYear]);
const months = useMemo(() => { const months = useMemo(() => {
if (monthsDisplay === "name") {
return getMonthOptions(translate);
}
return Array.from({ length: 12 }, (_, index) => { return Array.from({ length: 12 }, (_, index) => {
return index + 1; return index + 1;
}); });
}, []); }, [translate, monthsDisplay]);
const days = useMemo(() => { const days = useMemo(() => {
return Array.from( return Array.from(

View File

@ -1,5 +1,5 @@
import { removeAfterDot, roundToWhole } from "@/services/price"; import { removeAfterDot, roundToWhole } from "@/services/price";
import styles from "./styles.module.css"; import styles from "./styles.module.scss";
import Price, { Currency, Locale } from "@/components/PaymentTable/Price"; import Price, { Currency, Locale } from "@/components/PaymentTable/Price";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
@ -11,8 +11,10 @@ interface PriceItemProps {
active: boolean; active: boolean;
className?: string; className?: string;
classNameActive?: string; classNameActive?: string;
classNameDescription?: string;
currency: Currency; currency: Currency;
arrowElement?: React.ReactNode; arrowElement?: React.ReactNode;
description?: string;
click: (id: string) => void; click: (id: string) => void;
} }
@ -22,8 +24,10 @@ function PriceItem({
active, active,
className = "", className = "",
classNameActive = "", classNameActive = "",
classNameDescription = "",
currency = Currency.USD, currency = Currency.USD,
arrowElement, arrowElement,
description,
click, click,
}: PriceItemProps): JSX.Element { }: PriceItemProps): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -65,6 +69,11 @@ function PriceItem({
className={compatClassName()} className={compatClassName()}
> >
{removeAfterDot(_price.format())} {removeAfterDot(_price.format())}
{!!description?.length && (
<p className={`${styles.description} ${classNameDescription}`}>
{description}
</p>
)}
{arrowElement} {arrowElement}
</div> </div>
); );

View File

@ -1,40 +0,0 @@
.container {
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 60px;
height: 60px;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s, color 0.3s;
}
.active {
background-color: #D1ACF2;
border-color: #D1ACF2 !important;
color: #fff;
}
.popular {
border-color: #30bf52;
}
.popular:after {
content: 'Most Popular';
position: absolute;
width: 80px;
height: 20px;
left: -10px;
bottom: -25px;
background-color: #30bf52;
font-size: 9px;
font-weight: 500;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
}

View File

@ -0,0 +1,58 @@
.container {
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 60px;
height: 60px;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s, color 0.3s;
}
.active {
background-color: #d1acf2;
border-color: #d1acf2 !important;
color: #fff;
}
.popular {
border-color: #30bf52;
}
.popular:after {
content: "Most Popular";
position: absolute;
width: 80px;
height: 20px;
left: -10px;
bottom: -25px;
background-color: #30bf52;
font-size: 9px;
font-weight: 500;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
}
.description {
font-size: 14px;
font-weight: 600;
color: #6b7280;
}
:global(.dark-theme) {
.description {
color: #9ca3af;
}
.active {
& > .description {
color: #4f8de5;
}
}
}

View File

@ -12,11 +12,14 @@ interface PriceListProps {
classNameItem?: string; classNameItem?: string;
classNameItemActive?: string; classNameItemActive?: string;
classNamePricesContainer?: string; classNamePricesContainer?: string;
classNameDescription?: string;
currency?: Currency; currency?: Currency;
preActiveItems?: string[]; preActiveItems?: string[];
showArrow?: boolean; showArrow?: boolean;
productWidthArrow?: IFunnelPaymentVariant; productWidthArrow?: IFunnelPaymentVariant;
arrowElement?: React.ReactNode; arrowElement?: React.ReactNode;
displayMode?: "row" | "grid";
pricesDescription?: string[];
click: () => void; click: () => void;
} }
@ -30,11 +33,14 @@ function PriceList({
classNameItem = "", classNameItem = "",
classNameItemActive = "", classNameItemActive = "",
classNamePricesContainer = "", classNamePricesContainer = "",
classNameDescription = "",
preActiveItems = [], preActiveItems = [],
currency = Currency.USD, currency = Currency.USD,
showArrow = false, showArrow = false,
productWidthArrow, productWidthArrow,
arrowElement, arrowElement,
displayMode = "row",
pricesDescription = [],
}: PriceListProps): JSX.Element { }: PriceListProps): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [activeProductItem, setActiveProductItem] = const [activeProductItem, setActiveProductItem] =
@ -54,7 +60,9 @@ function PriceList({
}; };
return ( return (
<div className={`${styles.container} ${classNamePricesContainer}`}> <div
className={`${styles.container} ${classNamePricesContainer} ${styles[displayMode]}`}
>
{products.map((product, idx) => ( {products.map((product, idx) => (
<PriceItem <PriceItem
active={ active={
@ -64,8 +72,9 @@ function PriceList({
key={idx} key={idx}
value={getPrice(product)} value={getPrice(product)}
id={product.id} id={product.id}
className={classNameItem} className={`${classNameItem} ${styles.item} ${styles[displayMode]}`}
classNameActive={classNameItemActive} classNameActive={`${classNameItemActive} ${styles.itemActive} ${styles[displayMode]}`}
classNameDescription={classNameDescription}
click={priceItemClick} click={priceItemClick}
currency={currency} currency={currency}
arrowElement={ arrowElement={
@ -73,6 +82,7 @@ function PriceList({
? arrowElement ? arrowElement
: null : null
} }
description={pricesDescription[idx]}
/> />
))} ))}
</div> </div>

View File

@ -4,4 +4,36 @@
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
gap: 4px; gap: 4px;
&.grid {
width: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
}
.item {
&.grid {
width: 162px;
flex-direction: column;
gap: 8px;
height: 76px;
}
}
@media (max-width: 380px) {
.item {
&.grid {
width: 142px;
}
}
}
@media (max-width: 340px) {
.item {
&.grid {
width: 102px;
}
}
} }

View File

@ -39,6 +39,7 @@ export enum EUnleashFlags {
"v2CompatibilityReviewPage" = "v2-compatibility-review-page", "v2CompatibilityReviewPage" = "v2-compatibility-review-page",
"v2CompatibilityPathToEnteringBirthdate" = "v2-compatibility-path-to-entering-birthdate", "v2CompatibilityPathToEnteringBirthdate" = "v2-compatibility-path-to-entering-birthdate",
"v2CompatibilityTrialChoicePath" = "v2-compatibility-trial-choice-path", "v2CompatibilityTrialChoicePath" = "v2-compatibility-trial-choice-path",
"v2CompatibilityDateMonth" = "v2-compatibility-date-month",
} }
interface IUseUnleashProps<T extends EUnleashFlags> { interface IUseUnleashProps<T extends EUnleashFlags> {
@ -73,7 +74,7 @@ interface IVariants {
[EUnleashFlags.compatibilityV2TrialTextPrice]: "v0" | "v1" | "v2" | "v3"; [EUnleashFlags.compatibilityV2TrialTextPrice]: "v0" | "v1" | "v2" | "v3";
[EUnleashFlags.compatibilityV3TrialTextPrice]: "v0" | "v1" | "v2" | "v3"; [EUnleashFlags.compatibilityV3TrialTextPrice]: "v0" | "v1" | "v2" | "v3";
[EUnleashFlags.compatibilityV4TrialTextPrice]: "v0" | "v1" | "v2" | "v3"; [EUnleashFlags.compatibilityV4TrialTextPrice]: "v0" | "v1" | "v2" | "v3";
[EUnleashFlags.compatibilityV2TrialButton]: "v0" | "v1"; [EUnleashFlags.compatibilityV2TrialButton]: "v0" | "v1" | "v2" | "v3" | "v4";
[EUnleashFlags.palmistryV1TrialTextPrice]: "v0" | "v1" | "v2" | "v3"; [EUnleashFlags.palmistryV1TrialTextPrice]: "v0" | "v1" | "v2" | "v3";
[EUnleashFlags.v2CompatibilityScanResultNumbers]: 'off' | 'on'; [EUnleashFlags.v2CompatibilityScanResultNumbers]: 'off' | 'on';
[EUnleashFlags.v2CompatibilityScanInstructionImage]: 'v0' | 'v1'; [EUnleashFlags.v2CompatibilityScanInstructionImage]: 'v0' | 'v1';
@ -82,6 +83,7 @@ interface IVariants {
[EUnleashFlags.v2CompatibilityReviewPage]: 'v0' | 'v1' | 'v2' | 'v3' | 'v4'; [EUnleashFlags.v2CompatibilityReviewPage]: 'v0' | 'v1' | 'v2' | 'v3' | 'v4';
[EUnleashFlags.v2CompatibilityPathToEnteringBirthdate]: 'hide' | 'show'; [EUnleashFlags.v2CompatibilityPathToEnteringBirthdate]: 'hide' | 'show';
[EUnleashFlags.v2CompatibilityTrialChoicePath]: 'v0' | 'v1' | 'v2' | 'v3'; [EUnleashFlags.v2CompatibilityTrialChoicePath]: 'v0' | 'v1' | 'v2' | 'v3';
[EUnleashFlags.v2CompatibilityDateMonth]: 'v0' | 'v1';
} }
/** /**

49
src/utils/monthNames.ts Normal file
View File

@ -0,0 +1,49 @@
export interface MonthOption {
value: string;
label: string;
}
const monthKeys = [
"january",
"february",
"march",
"april",
"may",
"june",
"july",
"august",
"september",
"october",
"november",
"december",
];
export const getMonthOptions = (
translate: (key: string) => string
): MonthOption[] => {
return monthKeys.map((monthKey, index) => ({
value: String(index + 1),
label: translate(`months.${monthKey}`),
}));
};
export const getMonthName = (
monthNumber: string | number,
translate: (key: string) => string
): string => {
const index = Number(monthNumber) - 1;
const monthKey = monthKeys[index];
return monthKey ? translate(`months.${monthKey}`) : String(monthNumber);
};
export const getMonthNumber = (
monthName: string,
translate: (key: string) => string
): string => {
const index = monthKeys.findIndex(
(monthKey) => translate(`months.${monthKey}`) === monthName
);
return index !== -1 ? String(index + 1) : monthName;
};