forked from jamesp/sasa-membership
stuff changed:
- ui has been made 'kinda better' (after making it worse for a while lol - ESP rfid readers are now supported [ill upload the code for them in another repo later] - admin system has been secured a bit better and seems to be working well
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { membershipService, paymentService, MembershipTier, MembershipCreateData, PaymentCreateData } from '../services/membershipService';
|
||||
import { useFeatureFlags } from '../contexts/FeatureFlagContext';
|
||||
import SquarePaymentNew from './SquarePaymentNew';
|
||||
import { londonTodayDateInput } from '../utils/timezone';
|
||||
|
||||
interface MembershipSetupProps {
|
||||
onMembershipCreated: () => void;
|
||||
@@ -85,8 +86,10 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const startDate = new Date().toISOString().split('T')[0];
|
||||
const endDate = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
||||
const startDate = londonTodayDateInput();
|
||||
const endDateValue = new Date(`${startDate}T00:00:00Z`);
|
||||
endDateValue.setUTCFullYear(endDateValue.getUTCFullYear() + 1);
|
||||
const endDate = endDateValue.toISOString().split('T')[0];
|
||||
|
||||
const membershipData: MembershipCreateData = {
|
||||
tier_id: selectedTier.id,
|
||||
@@ -112,47 +115,38 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
|
||||
if (step === 'select') {
|
||||
return (
|
||||
<div className="card">
|
||||
<h3 style={{ marginBottom: '16px' }}>Choose Your Membership</h3>
|
||||
<div className="card member-card member-membership-setup">
|
||||
<div className="member-card-header">
|
||||
<div>
|
||||
<p className="member-card-kicker">Membership Setup</p>
|
||||
<h3>Choose Your Membership</h3>
|
||||
</div>
|
||||
</div>
|
||||
{error && <div className="alert alert-error">{error}</div>}
|
||||
|
||||
<div style={{ display: 'grid', gap: '16px' }}>
|
||||
<div className="membership-tier-grid">
|
||||
{tiers.map(tier => (
|
||||
<div
|
||||
key={tier.id}
|
||||
style={{
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '8px',
|
||||
padding: '16px',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = '#0066cc';
|
||||
e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 102, 204, 0.1)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = '#ddd';
|
||||
e.currentTarget.style.boxShadow = 'none';
|
||||
}}
|
||||
className="membership-tier-card"
|
||||
onClick={() => handleTierSelect(tier)}
|
||||
>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
|
||||
<h4 style={{ margin: 0, color: '#0066cc' }}>{tier.name}</h4>
|
||||
<span style={{ fontSize: '18px', fontWeight: 'bold', color: '#0066cc' }}>
|
||||
<div className="membership-tier-header">
|
||||
<h4>{tier.name}</h4>
|
||||
<span className="membership-tier-price">
|
||||
£{tier.annual_fee.toFixed(2)}/year
|
||||
</span>
|
||||
</div>
|
||||
<p style={{ margin: '8px 0', color: '#666', fontSize: '14px' }}>{tier.description}</p>
|
||||
<div style={{ backgroundColor: '#f5f5f5', padding: '12px', borderRadius: '4px' }}>
|
||||
<p className="membership-tier-description">{tier.description}</p>
|
||||
<div className="membership-tier-benefits">
|
||||
<strong>Benefits:</strong>
|
||||
<p style={{ marginTop: '4px', fontSize: '14px' }}>{tier.benefits}</p>
|
||||
<p>{tier.benefits}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: '20px', textAlign: 'center' }}>
|
||||
<div className="membership-setup-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
@@ -167,12 +161,17 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
|
||||
if (step === 'payment') {
|
||||
return (
|
||||
<div className="card">
|
||||
<h3 style={{ marginBottom: '16px' }}>Complete Payment</h3>
|
||||
<div className="card member-card member-membership-setup">
|
||||
<div className="member-card-header">
|
||||
<div>
|
||||
<p className="member-card-kicker">Membership Setup</p>
|
||||
<h3>Complete Payment</h3>
|
||||
</div>
|
||||
</div>
|
||||
{error && <div className="alert alert-error">{error}</div>}
|
||||
|
||||
{selectedTier && (
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div className="membership-summary-panel">
|
||||
<h4>Selected Membership: {selectedTier.name}</h4>
|
||||
<p><strong>Annual Fee:</strong> £{selectedTier.annual_fee.toFixed(2)}</p>
|
||||
<p><strong>Benefits:</strong> {selectedTier.benefits}</p>
|
||||
@@ -180,25 +179,19 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
)}
|
||||
|
||||
{!paymentMethod && (
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<h4 style={{ marginBottom: '16px' }}>Choose Payment Method</h4>
|
||||
<div className="membership-payment-stage">
|
||||
<h4 className="membership-payment-heading">Choose Payment Method</h4>
|
||||
|
||||
<div style={{ display: 'grid', gap: '12px' }}>
|
||||
<div className="membership-payment-options">
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={() => handlePaymentMethodSelect('square')}
|
||||
disabled={loading}
|
||||
style={{
|
||||
padding: '16px',
|
||||
textAlign: 'left',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
style={{ textAlign: 'left' }}
|
||||
>
|
||||
<div>
|
||||
<div className="membership-payment-option-copy">
|
||||
<strong>Credit/Debit Card</strong>
|
||||
<div style={{ fontSize: '14px', marginTop: '4px', opacity: 0.8 }}>
|
||||
<div>
|
||||
Pay securely with Square
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,17 +203,11 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
className="btn btn-secondary"
|
||||
onClick={() => handlePaymentMethodSelect('cash')}
|
||||
disabled={loading}
|
||||
style={{
|
||||
padding: '16px',
|
||||
textAlign: 'left',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
style={{ textAlign: 'left' }}
|
||||
>
|
||||
<div>
|
||||
<div className="membership-payment-option-copy">
|
||||
<strong>Cash Payment</strong>
|
||||
<div style={{ fontSize: '14px', marginTop: '4px', opacity: 0.8 }}>
|
||||
<div>
|
||||
Pay in person or by check
|
||||
</div>
|
||||
</div>
|
||||
@@ -229,7 +216,7 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: '20px', textAlign: 'center' }}>
|
||||
<div className="membership-setup-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
@@ -250,7 +237,7 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
onPaymentSuccess={handleSquarePaymentSuccess}
|
||||
onPaymentError={handleSquarePaymentError}
|
||||
/>
|
||||
<div style={{ marginTop: '20px', textAlign: 'center' }}>
|
||||
<div className="membership-setup-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary"
|
||||
@@ -268,26 +255,19 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
|
||||
{paymentMethod === 'cash' && createdMembershipId && (
|
||||
<div>
|
||||
<div style={{
|
||||
backgroundColor: '#fff3cd',
|
||||
border: '1px solid #ffeaa7',
|
||||
borderRadius: '4px',
|
||||
padding: '16px',
|
||||
marginBottom: '20px'
|
||||
}}>
|
||||
<div className="membership-cash-notice">
|
||||
<strong>Cash Payment Selected</strong>
|
||||
<p style={{ marginTop: '8px', marginBottom: 0 }}>
|
||||
<p>
|
||||
Your membership will be marked as pending until an administrator confirms payment receipt.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div className="membership-action-row">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={handleCashPayment}
|
||||
disabled={loading}
|
||||
style={{ marginRight: '10px' }}
|
||||
>
|
||||
{loading ? 'Processing...' : 'Confirm Cash Payment'}
|
||||
</button>
|
||||
@@ -314,13 +294,18 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
const isCashPayment = paymentMethod === 'cash';
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
<h3 style={{ marginBottom: '16px' }}>
|
||||
<div className="card member-card member-membership-setup">
|
||||
<div className="member-card-header">
|
||||
<div>
|
||||
<p className="member-card-kicker">Membership Setup</p>
|
||||
<h3>
|
||||
{isCashPayment ? 'Membership Application Submitted!' : 'Payment Successful!'}
|
||||
</h3>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedTier && (
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div className="membership-summary-panel">
|
||||
<h4>Your Membership Details:</h4>
|
||||
<p><strong>Tier:</strong> {selectedTier.name}</p>
|
||||
<p><strong>Annual Fee:</strong> £{selectedTier.annual_fee.toFixed(2)}</p>
|
||||
@@ -329,7 +314,7 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
{isCashPayment ? 'Pending' : 'Active'}
|
||||
</span>
|
||||
</p>
|
||||
<p style={{ fontSize: '14px', color: '#666', marginTop: '12px' }}>
|
||||
<p className="membership-confirm-copy">
|
||||
{isCashPayment
|
||||
? 'Your membership application has been submitted. An administrator will review and activate your membership once payment is confirmed.'
|
||||
: 'Thank you for your payment! Your membership has been activated and is now live. You can start enjoying your membership benefits immediately.'
|
||||
@@ -338,7 +323,7 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div className="membership-setup-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
@@ -354,4 +339,4 @@ const MembershipSetup: React.FC<MembershipSetupProps> = ({ onMembershipCreated,
|
||||
return null;
|
||||
};
|
||||
|
||||
export default MembershipSetup;
|
||||
export default MembershipSetup;
|
||||
|
||||
Reference in New Issue
Block a user