This commit is contained in:
dev.daminik00 2025-10-28 06:02:25 +01:00
parent 1adac2836b
commit 83d1faaa38
12 changed files with 39 additions and 39 deletions

View File

@ -26,7 +26,7 @@ export default function AddConsultantButton() {
onSuccess: async () => {
// Устанавливаем флаг навигации чтобы заблокировать повторные нажатия
setIsNavigating(true);
// Переходим на следующую страницу или на главную
if (navigation.hasNext) {
await navigation.goToNext();

View File

@ -23,9 +23,9 @@ export default function AddConsultantPage() {
return (
<>
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
/>
<Typography as="h2" size="xl" weight="semiBold" className={styles.title}>
{t("title")}

View File

@ -25,7 +25,7 @@ export default function AddGuidesButton() {
onSuccess: async () => {
// Устанавливаем флаг навигации чтобы заблокировать повторные нажатия
setIsNavigating(true);
// Переходим на следующую страницу или на главную
if (navigation.hasNext) {
await navigation.goToNext();

View File

@ -26,9 +26,9 @@ export default function AddGuidesPage() {
return (
<ProductSelectionProvider>
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
/>
<Typography as="h2" size="xl" weight="semiBold" className={styles.title}>
{t("title")}

View File

@ -30,11 +30,11 @@ export default function Progress({ items, activeItemIndex }: IProgressProps) {
// Фиксированные отступы от краев (центр кружочка = 50px от края)
const edgeOffset = 50; // 50px от края до центра кружочка
const totalItems = allItems.length;
// Рассчитываем позицию каждого элемента с равными отступами
const calculateItemPosition = (index: number) => {
if (totalItems === 1) return 50; // Центрируем если один элемент
// Распределяем элементы равномерно между краями
const availableWidth = containerWidth - (edgeOffset * 2);
const spacing = availableWidth / (totalItems - 1);
@ -47,14 +47,14 @@ export default function Progress({ items, activeItemIndex }: IProgressProps) {
// Находим все элементы прогресс бара
const items = elementRef.current.querySelectorAll(`.${styles.item}`);
let maxHeight = 0;
items.forEach((item) => {
const height = (item as HTMLElement).offsetHeight;
if (height > maxHeight) {
maxHeight = height;
}
});
setContainerHeight(maxHeight);
}
}, [allItems, containerWidth]);
@ -79,12 +79,12 @@ export default function Progress({ items, activeItemIndex }: IProgressProps) {
}, []);
return (
<div
className={clsx(styles.stickyWrapper, isScrolled && styles.scrolled)}
<div
className={clsx(styles.stickyWrapper, isScrolled && styles.scrolled)}
ref={wrapperRef}
>
<div
className={styles.container}
<div
className={styles.container}
ref={elementRef}
style={{
minHeight: containerHeight > 0 ? `${containerHeight}px` : undefined,

View File

@ -25,7 +25,7 @@ export default function VideoGuidesButton() {
onSuccess: async () => {
// Устанавливаем флаг навигации чтобы заблокировать повторные нажатия
setIsNavigating(true);
// Переходим на следующую страницу или на главную
if (navigation.hasNext) {
await navigation.goToNext();

View File

@ -7,10 +7,10 @@ import {
AdditionalPurchaseBanner,
ProductSelectionProvider,
Progress,
useMultiPageNavigationContext,
VideoGuidesButton,
VideoGuidesOffers,
VideoGuidesOffersSkeleton,
useMultiPageNavigationContext,
} from "@/components/domains/additional-purchases";
import { Typography } from "@/components/ui";
@ -27,9 +27,9 @@ export default function VideoGuidesPage() {
return (
<ProductSelectionProvider>
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
<Progress
items={progressItems}
activeItemIndex={navigation.currentIndex}
/>
<AdditionalPurchaseBanner />
<Typography as="h1" className={styles.title}>

View File

@ -101,7 +101,7 @@ export default function VideoGuideCard(props: VideoGuideCardProps) {
</Typography>
</div>
</div>
<Button
<Button
className={styles.buyButton}
onClick={(e) => {
e.preventDefault();

View File

@ -29,7 +29,7 @@ function VideoGuideCardWrapper({ videoGuide }: { videoGuide: VideoGuide }) {
const isClickable = videoGuide.isPurchased && videoGuide.videoLink;
const cardElement = (
<VideoGuideCard
<VideoGuideCard
name={videoGuide.name}
description={videoGuide.description}
imageUrl={videoGuide.imageUrl}
@ -46,8 +46,8 @@ function VideoGuideCardWrapper({ videoGuide }: { videoGuide: VideoGuide }) {
if (isClickable) {
return (
<Link
href={href}
<Link
href={href}
key={`video-guide-${videoGuide.id}`}
>
{cardElement}
@ -69,7 +69,7 @@ export default function VideoGuidesSection({ videoGuides }: VideoGuidesSectionPr
<Section title="Video Guides" contentClassName={styles.sectionContent}>
<Grid columns={columns} className={styles.grid}>
{videoGuides.map(videoGuide => (
<VideoGuideCardWrapper
<VideoGuideCardWrapper
key={`video-guide-${videoGuide.id}`}
videoGuide={videoGuide}
/>

View File

@ -22,7 +22,7 @@ export default function VideoGuideView({ name, description, videoLink }: VideoGu
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/,
/^([a-zA-Z0-9_-]{11})$/ // Direct video ID
];
for (const pattern of patterns) {
const match = url.match(pattern);
if (match) return match[1];
@ -31,7 +31,7 @@ export default function VideoGuideView({ name, description, videoLink }: VideoGu
};
const videoId = getYouTubeVideoId(videoLink);
const embedUrl = videoId
const embedUrl = videoId
? `https://www.youtube.com/embed/${videoId}?rel=0&modestbranding=1`
: videoLink;

View File

@ -12,7 +12,7 @@ export const loadCompatibility = () =>
export const loadMeditations = () =>
loadDashboard().then(d => d.meditations || []);
export const loadPalms = () =>
export const loadPalms = () =>
loadDashboard().then(d => d.palmActions || []);
export const loadPortraits = () =>

View File

@ -42,7 +42,7 @@ export function useVideoGuidePurchase(options: UseVideoGuidePurchaseOptions) {
startTransition(() => {
router.refresh();
});
// Убираем наш флаг, но isPending продолжит показывать loader
setIsProcessingPurchase(false);
},
@ -59,10 +59,10 @@ export function useVideoGuidePurchase(options: UseVideoGuidePurchaseOptions) {
const handlePurchase = useCallback(async () => {
// Сначала проверяем, не куплен ли уже продукт
setIsCheckingPurchase(true);
try {
const result = await checkVideoGuidePurchase(productKey);
if (result.data && result.data.isPurchased) {
// Продукт уже куплен! Показываем сообщение и обновляем страницу
addToast({
@ -70,26 +70,26 @@ export function useVideoGuidePurchase(options: UseVideoGuidePurchaseOptions) {
message: "You already own this video guide!",
duration: 3000,
});
setIsCheckingPurchase(false);
// Включаем лоадер на всей карточке
setIsProcessingPurchase(true);
// Даем небольшую задержку для плавного UX
await new Promise(resolve => setTimeout(resolve, 1000));
// Обновляем данные dashboard в transition
// isPending будет true пока данные загружаются
startTransition(() => {
router.refresh();
});
// Убираем наш флаг, но isPending продолжит показывать loader
setIsProcessingPurchase(false);
return;
}
// Продукт не куплен, продолжаем с checkout
setIsCheckingPurchase(false);
handleSingleCheckout({
@ -99,7 +99,7 @@ export function useVideoGuidePurchase(options: UseVideoGuidePurchaseOptions) {
} catch (error) {
console.error("Error checking purchase status:", error);
setIsCheckingPurchase(false);
// Даже если проверка не удалась, продолжаем с checkout
// чтобы не блокировать покупку
handleSingleCheckout({