1import { useState, useEffect } from 'react';
2import { apiFetch } from '../../lib/api';
3import PurchaseLicenseModal from '../../components/PurchaseLicenseModal';
5export default function TabOffice365() {
6 const [subscriptions, setSubscriptions] = useState([]);
7 const [loading, setLoading] = useState(true);
8 const [error, setError] = useState(null);
9 const [showPurchaseModal, setShowPurchaseModal] = useState(false);
15 const fetchSubscriptions = async () => {
19 const token = localStorage.getItem('token');
20 const res = await apiFetch('/office365/subscriptions', {
21 headers: { Authorization: `Bearer ${token}` }
25 const data = await res.json();
26 setSubscriptions(data.subscriptions || []);
28 throw new Error('Failed to fetch subscriptions');
31 console.error('Error fetching Office 365 subscriptions:', err);
32 setError(err.message || 'Error loading subscriptions');
38 const formatCurrency = (amount) => {
39 return new Intl.NumberFormat('en-AU', {
42 }).format(amount || 0);
45 const formatDate = (dateString) => {
46 if (!dateString) return 'N/A';
47 return new Date(dateString).toLocaleDateString('en-AU');
51 <div style={{ padding: '20px' }}>
52 <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
54 <h2>Office 365 Management</h2>
55 <p style={{ color: 'var(--text-secondary)', marginTop: '8px' }}>
56 Manage Microsoft 365 licenses through Pax8 integration
60 className="btn btn-primary"
61 onClick={() => setShowPurchaseModal(true)}
64 <span className="material-symbols-outlined">add</span>
73 border: '1px solid #fcc',
82 <div className="card" style={{ marginTop: '20px' }}>
84 <div style={{ textAlign: 'center', padding: '60px 20px', color: 'var(--text-secondary)' }}>
85 <div className="spinner" style={{ margin: '0 auto 16px' }}></div>
86 <p>Loading subscriptions...</p>
88 ) : subscriptions.length === 0 ? (
89 <div style={{ textAlign: 'center', padding: '60px 20px', color: 'var(--text-secondary)' }}>
90 <span className="material-symbols-outlined" style={{ fontSize: '64px', marginBottom: '16px', display: 'block', opacity: 0.5 }}>
93 <h3 style={{ color: 'var(--text)', marginBottom: '8px' }}>No subscriptions yet</h3>
94 <p>Purchase Microsoft 365 licenses through Pax8 to get started</p>
96 className="btn btn-primary"
97 onClick={() => setShowPurchaseModal(true)}
98 style={{ marginTop: '20px' }}
100 <span className="material-symbols-outlined">add</span>
101 Purchase Your First License
105 <table className="data-table">
111 <th>Monthly Cost</th>
113 <th>Next Billing</th>
118 {subscriptions.map((sub) => (
119 <tr key={sub.subscription_id}>
122 <strong>{sub.product_name || 'Unknown Product'}</strong>
124 <div style={{ fontSize: '12px', color: '#888' }}>
130 <td>{sub.customer_name || 'N/A'}</td>
131 <td>{sub.quantity || 0}</td>
132 <td>{formatCurrency(sub.monthly_price)}</td>
134 <span className={`status-badge ${(sub.status || 'active').toLowerCase()}`}>
135 {sub.status || 'Active'}
138 <td>{formatDate(sub.next_billing_date)}</td>
140 <div className="action-buttons">
142 className="btn btn-sm"
144 onClick={() => alert('View details coming soon')}
146 <span className="material-symbols-outlined">visibility</span>
149 className="btn btn-sm"
150 title="Edit subscription"
151 onClick={() => alert('Edit functionality coming soon')}
153 <span className="material-symbols-outlined">edit</span>
164 {/* Purchase Modal */}
165 {showPurchaseModal && (
166 <PurchaseLicenseModal
167 onClose={() => setShowPurchaseModal(false)}
169 fetchSubscriptions();
170 setShowPurchaseModal(false);