Переглянути джерело

Merge branch 'master' of http://139.224.214.174:3000/jerry/web-ui

jerry 1 місяць тому
батько
коміт
9fc9aabf4f

+ 67 - 17
src/app/refund-policy/page.tsx

@@ -1,9 +1,9 @@
 'use client';
 
-import { ShieldCheck, HelpCircle, AlertTriangle, Mail } from 'lucide-react';
+import { ShieldCheck, HelpCircle, AlertTriangle, Mail, Info, CreditCard, Smartphone, Wallet } from 'lucide-react';
 import { useLanguage } from '@/lib/i18n/LanguageContext';
 
-// 定义简单的品牌图标组件,避免引入额外的图标库
+// 定义简单的品牌图标组件
 const TelegramIcon = ({ className }) => (
   <svg viewBox="0 0 24 24" fill="currentColor" className={className}>
     <path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 11.944 0zm4.925 8.531l-1.97 9.28c-.145.658-.537.818-1.084.508l-3-2.21-1.446 1.394c-.16.16-.295.295-.605.295l.213-3.054 5.56-5.022c.242-.213-.054-.333-.373-.121l-6.869 4.326-2.96-.924c-.643-.204-.657-.643.136-.953l11.57-4.458c.535-.196 1.006.128.832.941z"/>
@@ -19,10 +19,9 @@ const WhatsAppIcon = ({ className }) => (
 export default function RefundPolicyPage() {
   const { t } = useLanguage();
 
-  // 请在这里填入你的真实账号
   const TELEGRAM_USERNAME = "Visafly Support"
-  const TELEGRAM_NUMBER = "+8617386033451"; // 例如: visafly_support
-  const WHATSAPP_NUMBER = "353892125284";  // 例如: 1234567890 (不需要加 + 号)
+  const TELEGRAM_NUMBER = "+8617386033451"; 
+  const WHATSAPP_NUMBER = "353892125284";  
 
   return (
     <div className="min-h-screen bg-slate-50 py-12 px-4 sm:px-6">
@@ -40,17 +39,70 @@ export default function RefundPolicyPage() {
         {/* Content */}
         <div className="p-8 sm:p-12 space-y-10 text-slate-700 leading-relaxed">
           
-          {/* Section 1: 全额退款 */}
+          {/* Section 1: 退款规则与网关手续费 */}
           <section>
             <h2 className="text-xl font-bold text-slate-900 mb-4 flex items-center gap-2">
               <span className="w-8 h-8 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center text-sm font-bold">1</span>
-              {t('refund.full_refund_title')}
+              {t('refund.standard_refund_title')}
             </h2>
-            <p className="mb-4">{t('refund.full_refund_desc')}</p>
+            
+            {/* 动态费用提示框 */}
+            <div className="bg-blue-50 border-l-4 border-blue-500 p-5 mb-6 rounded-r-lg">
+              <p className="font-bold flex items-center gap-2 mb-2 text-blue-900">
+                <Info size={18} className="text-blue-600" /> 
+                {t('refund.fee_notice_title')}
+              </p>
+              <p className="text-blue-800 text-sm mb-4">
+                {t('refund.fee_notice_desc')}
+              </p>
+
+              {/* 支付方式手续费明细表 */}
+              <div className="bg-white rounded-lg border border-blue-200 overflow-hidden">
+                <div className="grid grid-cols-2 bg-blue-100/50 p-3 text-sm font-semibold text-blue-900 border-b border-blue-200">
+                  <div>{t('refund.fee_table_method')}</div>
+                  <div className="text-right">{t('refund.fee_table_deduction')}</div>
+                </div>
+                
+                {/* Stripe */}
+                <div className="grid grid-cols-2 p-3 text-sm border-b border-blue-50 items-center">
+                  <div className="flex items-center gap-2 text-slate-700">
+                    <CreditCard size={16} className="text-slate-400"/> 
+                    {t('refund.fee_stripe')}
+                  </div>
+                  <div className="text-right text-orange-600 font-semibold bg-orange-50 px-2 py-1 rounded w-fit ml-auto">
+                    {t('refund.fee_stripe_val')}
+                  </div>
+                </div>
+
+                {/* WeChat / Alipay */}
+                <div className="grid grid-cols-2 p-3 text-sm border-b border-blue-50 items-center">
+                  <div className="flex items-center gap-2 text-slate-700">
+                    <Smartphone size={16} className="text-slate-400"/> 
+                    {t('refund.fee_wechat')}
+                  </div>
+                  <div className="text-right text-emerald-600 font-semibold bg-emerald-50 px-2 py-1 rounded w-fit ml-auto">
+                    {t('refund.fee_wechat_val')}
+                  </div>
+                </div>
+
+                {/* Others */}
+                <div className="grid grid-cols-2 p-3 text-sm items-center">
+                  <div className="flex items-center gap-2 text-slate-700">
+                    <Wallet size={16} className="text-slate-400"/> 
+                    {t('refund.fee_other')}
+                  </div>
+                  <div className="text-right text-slate-600 font-medium">
+                    {t('refund.fee_other_val')}
+                  </div>
+                </div>
+              </div>
+            </div>
+
+            <p className="mb-4 font-medium">{t('refund.standard_refund_desc')}</p>
             <ul className="list-disc pl-6 space-y-2 text-sm marker:text-blue-500">
-              <li>{t('refund.full_refund_item_1')}</li>
-              <li>{t('refund.full_refund_item_2')}</li>
-              <li>{t('refund.full_refund_item_3')}</li>
+              <li>{t('refund.standard_refund_item_1')}</li>
+              <li>{t('refund.standard_refund_item_2')}</li>
+              <li>{t('refund.standard_refund_item_3')}</li>
             </ul>
           </section>
 
@@ -60,9 +112,10 @@ export default function RefundPolicyPage() {
               <span className="w-8 h-8 rounded-full bg-orange-100 text-orange-600 flex items-center justify-center text-sm font-bold">2</span>
               {t('refund.no_refund_title')}
             </h2>
-            <div className="bg-orange-50 border-l-4 border-orange-400 p-4 mb-4 text-sm text-orange-800">
+            <div className="bg-orange-50 border-l-4 border-orange-400 p-4 mb-4 text-sm text-orange-800 rounded-r-lg">
               <p className="font-bold flex items-center gap-2 mb-1">
-                <AlertTriangle size={16} /> {t('refund.important_note')}
+                <AlertTriangle size={18} className="text-orange-600"/> 
+                {t('refund.important_note')}
               </p>
               <p>{t('refund.important_note_desc')}</p>
             </div>
@@ -96,14 +149,13 @@ export default function RefundPolicyPage() {
             </div>
           </section>
 
-          {/* Section 4: 联系方式 (已更新) */}
+          {/* Section 4: 联系方式 */}
           <section className="border-t pt-8">
             <h2 className="text-lg font-bold text-slate-900 mb-6 flex items-center gap-2">
               <HelpCircle size={20} className="text-slate-400" /> {t('refund.contact_title')}
             </h2>
             
             <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
-              {/* Email Button */}
               <a 
                 href="mailto:support@visafly.top" 
                 className="flex items-center gap-3 p-4 rounded-xl border border-slate-200 bg-white hover:border-blue-500 hover:bg-blue-50 transition-all group"
@@ -117,7 +169,6 @@ export default function RefundPolicyPage() {
                 </div>
               </a>
 
-              {/* Telegram Button */}
               <a 
                 href={`https://t.me/${TELEGRAM_NUMBER}`}
                 target="_blank"
@@ -133,7 +184,6 @@ export default function RefundPolicyPage() {
                 </div>
               </a>
 
-              {/* WhatsApp Button */}
               <a 
                 href={`https://wa.me/${WHATSAPP_NUMBER}`}
                 target="_blank"

+ 14 - 2
src/app/slots/page.tsx

@@ -12,6 +12,18 @@ const LOCATIONS = [
   { code: 'SG', name: 'Singapore', flag: '🇸🇬', cities: ['Singapore'] }
 ];
 
+const SUBSCRIPTION_BLACKLIST = [
+  { city: 'Dublin', country: 'France' },
+];
+
+const isBlacklisted = (slot: SlotSnapshot) => {
+  return SUBSCRIPTION_BLACKLIST.some(
+    (item) =>
+      item.city.toLowerCase() === slot.city?.toLowerCase() &&
+      item.country.toLowerCase() === slot.country?.toLowerCase()
+  );
+};
+
 export default function SlotDashboardPage() {
   const { t } = useLanguage();
   const [loading, setLoading] = useState(true);
@@ -211,7 +223,7 @@ export default function SlotDashboardPage() {
         ) : (
           <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
             {snapshots.map((slot) => (
-              <CitySlotCard key={slot.id} data={slot} />
+              <CitySlotCard key={slot.id} data={slot} isBlacklisted={isBlacklisted(slot)} />
             ))}
           </div>
         )}
@@ -219,4 +231,4 @@ export default function SlotDashboardPage() {
       </div>
     </div>
   );
-}
+}

+ 3 - 3
src/components/slots/CitySlotCard.tsx

@@ -22,7 +22,7 @@ export interface SlotSnapshot {
   };
 }
 
-export default function CitySlotCard({ data }: { data: SlotSnapshot }) {
+export default function CitySlotCard({ data, isBlacklisted = false }: { data: SlotSnapshot; isBlacklisted?: boolean }) {
   const { t, lang } = useLanguage();
   const router = useRouter();
   
@@ -121,7 +121,7 @@ export default function CitySlotCard({ data }: { data: SlotSnapshot }) {
   const slotCity = data.city;
   const slotCountry = data.country;
   const slotVisaType = data.visa_type;
-  const canSubscribe = Boolean(slotRoutingKey);
+  const canSubscribe = Boolean(slotRoutingKey) && !isBlacklisted;
 
   const handleSubscribe = () => {
     if (!slotRoutingKey) return;
@@ -258,7 +258,7 @@ export default function CitySlotCard({ data }: { data: SlotSnapshot }) {
           >
             {t('slots.subscribe_notification') || 'Subscribe for updates'}
           </button>
-          {!canSubscribe && (
+          {!canSubscribe && !isBlacklisted && (
             <p className="text-xs text-slate-400 mt-1">
               {t('slots.subscribe_unavailable') || 'Routing info unavailable'}
             </p>

+ 15 - 1
src/lib/i18n/locales/en.ts

@@ -288,7 +288,21 @@ export const en = {
     full_refund_item_1: 'You have paid for the order, but our system has not yet started any booking operations (Status is Pending).',
     full_refund_item_2: 'Duplicate charges caused by Visafly system errors.',
     full_refund_item_3: 'We failed to successfully book a slot for you within the promised timeframe (usually 30 days, depending on the service).',
-    
+    standard_refund_title: "Refund Rules & Processing Fees",
+    fee_notice_title: "Important: Payment Gateway Fees",
+    fee_notice_desc: "Depending on the payment method used, third-party payment gateways may charge a non-refundable processing or management fee. For eligible refunds, the actual refunded amount will be deducted based on your original payment method:",
+    fee_table_method: "Payment Method",
+    fee_table_deduction: "Deduction (Processing Fee)",
+    fee_stripe: "Stripe (Credit Card / Apple Pay, etc.)",
+    fee_stripe_val: "7% Deduction",
+    fee_wechat: "WeChat Pay / Alipay",
+    fee_wechat_val: "Full Refund (0% Deduction)",
+    fee_other: "Other Payment Methods",
+    fee_other_val: "Varies by gateway",
+    standard_refund_desc: "After deducting the applicable fees above, you may request a refund under the following conditions:",
+    standard_refund_item_1: "The service has not yet been processed and you request a cancellation.",
+    standard_refund_item_2: "We are unable to provide the service due to our system failure.",
+    standard_refund_item_3: "Other special circumstances confirmed and approved by our customer support.",
     no_refund_title: 'Non-refundable Scenarios',
     important_note: 'Important Note',
     important_note_desc: 'Once the service enters the execution stage or incurs third-party fees, refunds will be restricted.',

+ 16 - 8
src/lib/i18n/locales/zh.ts

@@ -281,14 +281,22 @@ export const zh = {
   },
   refund: {
     title: '退款政策 & 服务条款',
-    subtitle: '为了保障您的权益,请仔细阅读以下条款',
-    
-    full_refund_title: '全额退款情形',
-    full_refund_desc: '在以下情况下,您可以申请全额退款:',
-    full_refund_item_1: '您已支付订单,但我们的系统尚未开始执行任何预约操作(Status 为 Pending)。',
-    full_refund_item_2: '由于 Visafly 系统故障导致重复扣款。',
-    full_refund_item_3: '我们在承诺的时限内(通常为 30 天,具体视服务而定)未能为您成功预约到名额。',
-    
+    subtitle: '为了保障您的权益,请仔细阅读以下条款',    
+    standard_refund_title: "退款规则与手续费说明",
+    fee_notice_title: "重要:第三方支付网关手续费",
+    fee_notice_desc: "因支付渠道不同,部分第三方支付网关在订单支付成功时会收取不可退还的手续费或管理费。符合退款条件的订单,实际退款金额将根据您下单时使用的支付方式扣除相应的费用:",
+    fee_table_method: "支付方式",
+    fee_table_deduction: "退款扣除费用",
+    fee_stripe: "Stripe (信用卡 / Apple Pay 等)",
+    fee_stripe_val: "扣除 7% 手续费",
+    fee_wechat: "微信支付 / 支付宝 (WeChat / Alipay)",
+    fee_wechat_val: "全额退款 (0 扣除)",
+    fee_other: "其他支付方式",
+    fee_other_val: "视具体网关规定而定",
+    standard_refund_desc: "在扣除上述对应手续费后,符合以下情况时,您可以申请退款:",
+    standard_refund_item_1: "服务尚未开始处理且您主动要求取消订单。",
+    standard_refund_item_2: "由于我们的系统故障导致服务无法提供。",
+    standard_refund_item_3: "其他经由客服确认符合退款标准的特殊情况。",
     no_refund_title: '无法退款情形',
     important_note: '重要提示',
     important_note_desc: '一旦服务进入执行阶段或产生第三方费用,退款将受到限制。',