From 50a7717c1581afd65f4089bbe557dc77286074cc Mon Sep 17 00:00:00 2001 From: oguz ozturk Date: Mon, 12 Jan 2026 18:54:39 +0300 Subject: [PATCH] feat: Add customer password change functionality in admin panel --- backend/app/routes/customers.py | 22 ++++ frontend/src/pages/Customers.jsx | 150 +++++++++++++++++++++++ frontend/src/services/customerService.js | 7 ++ 3 files changed, 179 insertions(+) diff --git a/backend/app/routes/customers.py b/backend/app/routes/customers.py index 43c5d24..979277e 100644 --- a/backend/app/routes/customers.py +++ b/backend/app/routes/customers.py @@ -191,6 +191,28 @@ def update_customer_status(current_admin, customer_id): return jsonify({'error': str(e)}), 500 +@customers_bp.route('//password', methods=['PUT']) +@token_required +def change_customer_password(current_admin, customer_id): + """Change customer password""" + try: + data = request.get_json() + + result = call_customer_api( + f'/api/admin/customers/{customer_id}/password', + method='PUT', + data=data + ) + + if result and result.get('status') == 'success': + return jsonify(result), 200 + else: + return jsonify(result or {'error': 'Failed to change password'}), 500 + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + @customers_bp.route('/stats', methods=['GET']) @token_required def get_customer_stats(current_admin): diff --git a/frontend/src/pages/Customers.jsx b/frontend/src/pages/Customers.jsx index 0204950..d0e355a 100644 --- a/frontend/src/pages/Customers.jsx +++ b/frontend/src/pages/Customers.jsx @@ -14,6 +14,7 @@ const Customers = () => { const [showPlanModal, setShowPlanModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + const [showPasswordModal, setShowPasswordModal] = useState(false); const [showToast, setShowToast] = useState(false); const [toastMessage, setToastMessage] = useState(''); const [toastType, setToastType] = useState('success'); // success, error @@ -121,6 +122,18 @@ const Customers = () => { } }; + const handleChangePassword = async (customerId, passwordData) => { + try { + await customerService.changeCustomerPassword(customerId, passwordData); + setShowPasswordModal(false); + setSelectedCustomer(null); + showSuccessToast('Password changed successfully!'); + } catch (err) { + console.error('Failed to change password:', err); + showErrorToast('Failed to change password: ' + (err.response?.data?.message || err.message)); + } + }; + const getStatusBadge = (isActive, subscriptionStatus) => { if (!isActive) { return Inactive; @@ -256,6 +269,16 @@ const Customers = () => { > 📦 + {customer.subscription_status === 'suspended' || !customer.is_active ? ( + + +
+

+ Customer: {customer.full_name} ({customer.email}) +

+
+ + {error && ( +
+

{error}

+
+ )} + +
+
+ + setNewPassword(e.target.value)} + className="input w-full" + placeholder="Enter new password (min 8 characters)" + disabled={loading} + autoFocus + /> +
+ +
+ + setConfirmPassword(e.target.value)} + className="input w-full" + placeholder="Confirm new password" + disabled={loading} + /> +
+ +
+ + +
+
+ + + ); +}; + export default Customers; diff --git a/frontend/src/services/customerService.js b/frontend/src/services/customerService.js index 6978b2a..4876501 100644 --- a/frontend/src/services/customerService.js +++ b/frontend/src/services/customerService.js @@ -58,6 +58,12 @@ export const getCustomerStats = async () => { return response.data; }; +// Change customer password +export const changeCustomerPassword = async (customerId, passwordData) => { + const response = await api.put(`/api/customers/${customerId}/password`, passwordData); + return response.data; +}; + export default { getCustomers, getCustomer, @@ -68,5 +74,6 @@ export default { updateCustomerPlan, updateCustomerStatus, getCustomerStats, + changeCustomerPassword, };