/** * 抽奖组件共享类型定义 * * 包含所有抽奖组件(WheelLottery, ProductLottery 等)共用的类型、接口和常量。 * * @module LotterySharedTypes * @date 2026-04-07 */ import type { Theme, Img } from '../../types/props.js'; export type { Theme, Img }; /** * 奖品(Prize) * * 代表抽奖活动中的一个奖品,包含显示所需的所有信息。 * * @example * ```tsx * const prize: Prize = { * prizeKey: 'prize-001', * name: 'Anker Prime Charger (100W, 3 Ports, GaN)', * image: { url: 'https://images.unsplash.com/photo-123', alt: 'Charger' }, * rank: '1st', * price: '$79.99' * } * ``` */ export interface Prize { /** * 唯一标识符,用于 React key 和中奖结果匹配 */ prizeKey: string; /** * 奖品名称,显示在转盘和奖池中 * @maxLength 100 */ name: string; /** * 奖品图片对象,包含 url 和 alt */ image: Img; /** * 排名标识,仅在 Prize Pool 中显示 * @optional */ rank?: '1st' | '2nd' | '3rd'; /** * 价格或折扣信息,显示在奖池中 * @example "$99.99" | "12% Off" * @optional */ price?: string; } /** * 中奖信息(WinningInfo) * * 代表一条中奖记录,用于底部滚动条展示,营造活动氛围。 * * @example * ```tsx * const winningInfo: WinningInfo = { * winningKey: 'win-001', * userName: 'Shuqi***', * prizeName: '12% Off Discount', * timestamp: 1702800000000 * } * ``` */ export interface WinningInfo { /** * 唯一标识符 */ winningKey: string; /** * 用户名(已脱敏),如 "Shuqi***" * @note 假设传入的用户名已经过脱敏处理,组件内部不再处理 */ userName: string; /** * 中奖奖品名称 */ prizeName: string; /** * 中奖时间戳(毫秒) * @optional */ timestamp?: number; } /** * 获取机会方式类型 */ export type ChanceMethodType = 'share' | 'points' | 'refer' | string; /** * 获取机会方式状态 */ export type ChanceMethodStatus = 'pending' | 'completed' | 'used'; /** * 获取机会方式(ChanceMethod) * * 代表一种获取抽奖机会的方式,支持灵活配置(分享、积分、推荐等)。 * * @example * ```tsx * const chanceMethod: ChanceMethod = { * methodKey: 'share-001', * type: 'share', * title: 'Share on your socials', * description: 'Share this event on your social media', * buttonText: 'Redeem now', * onClick: () => console.log('Share clicked'), * disabled: false, * status: 'pending' * } * ``` */ export interface ChanceMethod { /** * 唯一标识符 */ methodKey: string; /** * 方式类型,支持预定义类型('share', 'points', 'refer')或自定义类型 */ type: ChanceMethodType; /** * 方式标题,如 "Share on your socials" */ title: string; /** * 详细说明文字 */ description: string; /** * 按钮文案,默认 "Redeem now" * @default "Redeem now" * @optional */ buttonText?: string; completed?: string; used?: string; /** * 未登录时点击 GO 按钮的回调 * @example * ```tsx * onLoginRequired={() => { * // 打开登录弹窗或跳转登录页 * router.push('/login') * }} * ``` */ onLoginRequired?: () => void; /** * 点击按钮时的回调函数 * @note 业务逻辑(如积分扣除、分享验证)由父组件处理 */ onClick: () => void; /** * 是否禁用该方式 * @default false * @optional */ disabled?: boolean; /** * 获取机会方式的状态 * - pending: 未完成(默认状态) * - completed: 已完成/已获得 * - used: 已使用 * @default "pending" * @optional */ status?: ChanceMethodStatus; /** * 是否显示加载状态 * @default false * @optional */ loading?: boolean; /** * 是否在点击时打开分享弹窗 * @default false * @optional */ openShareModal?: boolean; } /** * 用户数据(UserData) * * 代表当前用户的抽奖相关数据 * * @example * ```tsx * const userData: UserData = { * isLoggedIn: true, * availableChances: 3, * wonPrizes: [ * { id: 'prize-001', name: 'Charger', image: 'https://...', timestamp: 1702800000000 } * ] * } * ``` */ export interface UserData { /** * 用户是否已登录 */ isLoggedIn: boolean; /** * 当前可使用的抽奖次数 * @default 0 */ availableChances: number; /** * 总机会数(用于显示进度,例如 "3/5") * @default undefined * @optional */ totalChances?: number; /** * 已获得的奖品列表 * @optional */ wonPrizes?: Array; /** * 用户电子邮箱(可选,用于发送中奖通知等) * @optional */ email?: string; } /** * 缓动函数类型 */ export type EasingFunction = 'ease-out' | 'ease-in-out' | 'linear'; /** * 复制操作相关文案配置(公共类型) * 用于所有包含复制功能的组件 */ export interface CopyTextConfig { /** * 复制按钮文本 * @default "COPY" */ copyText?: string; /** * 复制成功后的按钮文本 * @default "COPIED" */ copiedText?: string; } /** * 优惠码相关配置(公共类型) * 用于所有展示优惠码的组件 */ export interface CouponConfig { /** * 代码文本前缀 * @default "CODE:" */ codeText?: string; /** * 优惠码 */ couponCode?: string; /** * 优惠码过期时间 */ expiresAt?: string; /** * 优惠券折扣文本(例如 "20%") */ couponDiscount?: string; /** * 优惠券单位文本 * @default "Off" */ couponUnit?: string; } /** * 奖励时间文案配置(公共类型) */ export interface PrizeTimeTextConfig { /** * 奖励时间文本前缀 * @default "Prize time:" */ prizeText?: string; } /** * 中奖弹窗配置(WinnerModalConfig) * * 用于配置中奖弹窗的展示内容,通常由抽奖接口返回提供 * * @example * ```tsx * const winnerModalConfig: WinnerModalConfig = { * title: 'Congratulations!', * prizeTitle: 'Anker Prime Charger', * prizeImage: 'https://...', * prizeDescription: 'High-speed charging for all your devices', * learnMoreUrl: 'https://...', * learnMoreText: 'View Details', * couponCode: 'ANKER2024', * expiresAt: '2024-12-31', * couponDiscount: '20%', * couponUnit: 'Off', * confirmText: 'Claim Now' * } * ``` */ export interface WinnerModalConfig extends CopyTextConfig, CouponConfig, PrizeTimeTextConfig { /** * 中奖弹窗标题 * @default "You Have Won" * @optional */ title?: string; /** * 中奖弹窗奖品标题(优先级高于 prize.name) * @optional */ prizeTitle?: string; /** * 中奖弹窗奖品图片 URL(优先级高于 prize.image) * @optional */ prizeImage?: string; /** * 中奖弹窗奖品详情描述 * @optional */ prizeDescription?: string; /** * 中奖弹窗 Learn More 链接 * @optional */ learnMoreUrl?: string; /** * 中奖弹窗 Learn More 按钮文本 * @default "Learn More" * @optional */ learnMoreText?: string; /** * 中奖弹窗确认按钮文本 * @default "Okay, Got It" * @optional */ confirmText?: string; /** 确认按钮跳转链接,配置后点击按钮将在新标签页打开此链接 @optional */ confirmUrl?: string; } /** * Rules 弹窗配置 * * @example * ```tsx * rulesModalConfig={{ * rulesData: [ * { item: '$100 instead of $200, 10 tickets/day.' }, * { item: '$100 for $120, 50 tickets/day.' } * ], * rulesText: 'Game Rules', * rulesTitle: 'Activity Rules' * }} * ``` */ export interface RulesModalConfig { /** * 规则数据列表 * @optional */ rulesData?: Array<{ /** * 规则项内容 */ item: string; }>; /** * Rules 按钮文本 * @default "Rules" * @optional */ rulesText?: string; /** * 弹窗标题 * @default "Rules" * @optional */ rulesTitle?: string; } /** * My Rewards 弹窗配置 * * @example * ```tsx * myRewardsModalConfig={{ * rewardsData: [ * { * id: '1', * name: 'Anker Charger', * code: 'ANKER2024', * status: 'Available', * prizeTime: '2024-01-01', * showCopyCode: true * } * ], * myRewardsText: 'My Prizes', * codeText: 'CODE:', * copyText: 'COPY', * prizeText: 'Prize time:', * emptyText: 'No rewards yet' * }} * ``` */ export interface MyRewardsModalConfig extends CopyTextConfig, PrizeTimeTextConfig { /** * 奖励数据列表 * @optional */ rewardsData?: Array<{ /** * 奖励 ID */ id: string; /** * 奖励名称 */ name: string; /** * 优惠码(可选) */ code?: string; /** * 状态 */ status: 'Available' | 'Expired' | 'Used'; /** * 奖励时间 */ prizeTime?: string; /** * 是否可复制码 */ showCopyCode?: boolean; }>; /** * My Rewards 按钮文本 * @default "My Rewards" * @optional */ myRewardsText?: string; /** * 弹窗标题 * @default "My Rewards" * @optional */ myRewardsTitle?: string; /** * 代码文本前缀 * @default "CODE:" * @optional */ codeText?: string; /** * 空状态提示文本 * @default "No rewards yet" * @optional */ emptyText?: string; } /** * 错误弹窗配置 * @example * ```tsx * errorModalConfig={{ * title: 'Oops!', * message: 'Something went wrong during the lottery process.', * confirmText: 'OK, I get' * }} * ``` */ export interface ErrorModalConfig { /** * 弹窗标题 * @default "Oops!" * @optional */ title?: string; /** * 错误消息内容 * @default "Something went wrong during the lottery process." * @optional */ message?: string; /** * 确认按钮文本 * @default "OK, I get" * @optional */ confirmText?: string; } /** * 社交平台类型 */ export type SocialPlatform = 'facebook' | 'twitter' | 'instagram' | 'linkedin' | 'tiktok' | 'youtube'; /** * 社交平台配置 */ export interface SharePlatformConfig { /** * 平台类型 */ platform: SocialPlatform; /** * 平台名称 */ name: string; /** * 分享 URL(可选,如果提供则直接跳转) */ url?: string; /** * 点击回调(如果提供 url 则此回调会在跳转前执行) */ onClick?: () => void; /** * 是否禁用 */ disabled?: boolean; } /** * 分享弹窗配置 */ export interface ShareModalConfig { /** * 弹窗标题 * @default "Share to Get More Chances" */ title?: string; /** * 副标题/引导文案 * @default "Share to Play Again Keep Trying! You Could Still Win Big!" */ subtitle?: string; /** * 底部提示文案 * @default "Note: Maximum of 3 times per participant." */ note?: string; /** * 社交平台配置列表 */ platforms?: SharePlatformConfig[]; /** * 分享成功回调 */ onShareSuccess?: (platform: SocialPlatform) => void; } /** * PrizePool 奖品池组件 Props */ export interface PrizePoolProps { /** * 主题模式 * @optional */ theme?: Theme; /** * 奖品列表(通常是全部 8 个奖品) */ prizes: Prize[]; /** * 标题文本 * @default "Prize Pool" */ title?: string; /** * 中奖人名单数据 * @optional */ winningInfos?: WinningInfo[]; /** * 自定义类名 */ className?: string; } /** 活动机制模式 */ export type ChanceMechanismType = 'methods' | 'input'; /** 输入框配置(仅 mechanismType='input' 时使用) */ export interface ChanceInputConfig { /** 输入框占位文本 @default "Enter your order number" */ placeholder?: string; /** 提交按钮文案 @default "Spin and Win" */ submitText?: string; /** 输入值提交回调 */ onSubmit?: (value: string) => void | Promise; /** 是否正在提交 */ isSubmitting?: boolean; /** 输入框类型 @default "text" */ inputType?: 'text' | 'email' | 'number'; /** 验证正则 (可选) */ validationPattern?: string; /** 验证失败提示文案 */ validationErrorText?: string; /** 输入框默认值(如登录用户 email,支持异步填充) @optional */ defaultValue?: string; } /** * ChanceMethods 获取机会组件 Props */ export interface ChanceMethodsProps { /** * 主题模式 * @optional */ theme?: Theme; /** * 获取机会方式列表 */ methods: ChanceMethod[]; /** * 标题文本 * @default "Want more chances to win?" */ title?: string; /** * 副标题(可选) */ subtitle?: string; /** * 底部提示文本(可选) */ footerNote?: string; /** * 登录用户数据(可选) * @optional */ userData?: UserData; /** * 打开分享弹窗回调(可选) * @optional */ onOpenShareModal?: () => void; /** * 徽章文案 * @default "Chance +1" */ chanceBadgeText?: string; /** * 已完成状态文案 * @default "Completed" */ completedText?: string; /** * 已使用状态文案 * @default "Used" */ usedText?: string; /** * 加载中文案 * @default "Loading..." */ loadingText?: string; /** * 自定义类名 */ className?: string; /** 活动机制模式 @default 'methods' */ mechanismType?: ChanceMechanismType; /** 输入框配置(仅 mechanismType='input' 时使用) */ inputConfig?: ChanceInputConfig; } /** * WinnerModal 中奖弹窗组件 Props */ export interface WinnerModalProps extends CopyTextConfig, CouponConfig, PrizeTimeTextConfig { /** * 是否显示弹窗 */ isOpen: boolean; /** * 中奖奖品信息 */ prize: Prize | null; /** * 弹窗标题(可选,默认 "You Have Won") */ title?: string; /** * 奖品标题(可选,默认使用 prize.name) */ prizeTitle?: string; /** * 奖品图片 URL(可选,默认使用 prize.image) */ prizeImage?: string; /** * 奖品详情描述(可选) */ prizeDescription?: string; /** * Learn More 链接(可选) */ learnMoreUrl?: string; /** * Learn More 按钮文本(可选,默认 "Learn More") */ learnMoreText?: string; /** * 复制码点击回调 */ onCopyCode?: (code: string) => void; /** * 关闭弹窗回调 */ onClose: () => void; /** * 确认按钮文本(可选,默认 "Okay, Got It") */ confirmText?: string; /** 确认按钮跳转链接 @optional */ confirmUrl?: string; /** * 确认按钮点击回调(可选) */ onConfirm?: () => void; /** * 自定义类名 */ className?: string; } /** * 默认获取机会方式(3种) * @note 父组件需要覆盖 onClick 回调以实现具体业务逻辑 */ export declare const DEFAULT_CHANCE_METHODS: ChanceMethod[]; /** * 检查是否为有效的 Prize 对象 * @param value 待检查的值 * @returns 是否为有效的 Prize */ export declare function isPrize(value: unknown): value is Prize; /** * 检查是否为有效的 ChanceMethod 对象 * @param value 待检查的值 * @returns 是否为有效的 ChanceMethod */ export declare function isChanceMethod(value: unknown): value is ChanceMethod; /** * 检查是否为有效的 WinningInfo 对象 * @param value 待检查的值 * @returns 是否为有效的 WinningInfo */ export declare function isWinningInfo(value: unknown): value is WinningInfo; /** * 抽奖回调函数类型 */ export type OnSpinEndCallback = (prize: Prize) => void; /** * 获取机会点击回调函数类型 */ export type OnChanceMethodClick = () => void;