vasuzex 2.1.16 → 2.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ /**
2
+ * ApprovalStatusCell Component
3
+ *
4
+ * Reusable read-only status pill for approval workflows
5
+ * Displays status with icon and soft background colors
6
+ *
7
+ * @module components/DataTable/CellComponents
8
+ */
9
+
10
+ import React from 'react';
11
+ import PropTypes from 'prop-types';
12
+ import { CheckCircle, XCircle, Clock } from 'lucide-react';
13
+
14
+ const STATUS_CONFIG = {
15
+ pending: {
16
+ icon: Clock,
17
+ label: 'Pending',
18
+ bgClass: 'bg-amber-50 dark:bg-amber-950/30',
19
+ textClass: 'text-amber-700 dark:text-amber-400',
20
+ },
21
+ approved: {
22
+ icon: CheckCircle,
23
+ label: 'Approved',
24
+ bgClass: 'bg-emerald-50 dark:bg-emerald-950/30',
25
+ textClass: 'text-emerald-700 dark:text-emerald-400',
26
+ },
27
+ rejected: {
28
+ icon: XCircle,
29
+ label: 'Rejected',
30
+ bgClass: 'bg-rose-50 dark:bg-rose-950/30',
31
+ textClass: 'text-rose-700 dark:text-rose-400',
32
+ },
33
+ };
34
+
35
+ /**
36
+ * ApprovalStatusCell - Professional status indicator
37
+ *
38
+ * @param {Object} props
39
+ * @param {string} props.status - Approval status: 'pending'|'approved'|'rejected'
40
+ * @returns {JSX.Element}
41
+ */
42
+ export function ApprovalStatusCell({ status }) {
43
+ const config = STATUS_CONFIG[status] || STATUS_CONFIG.pending;
44
+ const Icon = config.icon;
45
+
46
+ return (
47
+ <span
48
+ className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md text-xs font-medium ${config.bgClass} ${config.textClass}`}
49
+ >
50
+ <Icon className="h-3.5 w-3.5" />
51
+ {config.label}
52
+ </span>
53
+ );
54
+ }
55
+
56
+ ApprovalStatusCell.propTypes = {
57
+ status: PropTypes.oneOf(['pending', 'approved', 'rejected']).isRequired,
58
+ };
59
+
60
+ export default ApprovalStatusCell;
@@ -0,0 +1,212 @@
1
+ /**
2
+ * RowActionsCell Component
3
+ *
4
+ * Reusable actions cell with primary icons + overflow menu pattern
5
+ * Follows modern admin dashboard design (Amazon Seller/Stripe/Blinkit)
6
+ *
7
+ * @module components/DataTable/CellComponents
8
+ */
9
+
10
+ import React, { useState, useRef, useEffect } from 'react';
11
+ import PropTypes from 'prop-types';
12
+ import { Eye, Edit2, MoreVertical, CheckCircle, XCircle, History, Power, Trash2 } from 'lucide-react';
13
+ import { Link } from 'react-router-dom';
14
+
15
+ /**
16
+ * RowActionsCell - Professional actions menu for data tables
17
+ *
18
+ * @param {Object} props
19
+ * @param {Object} props.row - Row data object
20
+ * @param {Function} props.onView - View action handler
21
+ * @param {Function} props.onEdit - Edit action handler (optional if editPath provided)
22
+ * @param {string} props.editPath - Edit page path (will be passed to Link)
23
+ * @param {Function} props.onToggle - Toggle status handler
24
+ * @param {Function} props.onDelete - Delete action handler
25
+ * @param {Function} props.onApprove - Approve action handler (approval workflows)
26
+ * @param {Function} props.onReject - Reject action handler (approval workflows)
27
+ * @param {Function} props.onViewHistory - View approval history handler
28
+ * @param {boolean} props.hasApproval - Whether to show approval actions (default: false)
29
+ * @returns {JSX.Element}
30
+ */
31
+ export function RowActionsCell({
32
+ row,
33
+ onView,
34
+ onEdit,
35
+ editPath,
36
+ onToggle,
37
+ onDelete,
38
+ onApprove,
39
+ onReject,
40
+ onViewHistory,
41
+ hasApproval = false,
42
+ }) {
43
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
44
+ const menuRef = useRef(null);
45
+ const isPending = hasApproval && row.approval_status === 'pending';
46
+
47
+ // Close menu when clicking outside
48
+ useEffect(() => {
49
+ const handleClickOutside = (event) => {
50
+ if (menuRef.current && !menuRef.current.contains(event.target)) {
51
+ setIsMenuOpen(false);
52
+ }
53
+ };
54
+
55
+ if (isMenuOpen) {
56
+ document.addEventListener('mousedown', handleClickOutside);
57
+ return () => document.removeEventListener('mousedown', handleClickOutside);
58
+ }
59
+ }, [isMenuOpen]);
60
+
61
+ return (
62
+ <div className="flex items-center gap-2">
63
+ {/* Primary Actions - Always Visible */}
64
+ <button
65
+ onClick={() => onView(row)}
66
+ className="p-1.5 text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors dark:text-gray-400 dark:hover:text-blue-400 dark:hover:bg-blue-950/30"
67
+ title="View Details"
68
+ aria-label="View Details"
69
+ >
70
+ <Eye className="h-4 w-4" />
71
+ </button>
72
+
73
+ {editPath ? (
74
+ <Link
75
+ to={editPath}
76
+ className="p-1.5 text-gray-600 hover:text-emerald-600 hover:bg-emerald-50 rounded-md transition-colors dark:text-gray-400 dark:hover:text-emerald-400 dark:hover:bg-emerald-950/30"
77
+ title="Edit"
78
+ aria-label="Edit"
79
+ >
80
+ <Edit2 className="h-4 w-4" />
81
+ </Link>
82
+ ) : (
83
+ onEdit && (
84
+ <button
85
+ onClick={() => onEdit(row)}
86
+ className="p-1.5 text-gray-600 hover:text-emerald-600 hover:bg-emerald-50 rounded-md transition-colors dark:text-gray-400 dark:hover:text-emerald-400 dark:hover:bg-emerald-950/30"
87
+ title="Edit"
88
+ aria-label="Edit"
89
+ >
90
+ <Edit2 className="h-4 w-4" />
91
+ </button>
92
+ )
93
+ )}
94
+
95
+ {/* Overflow Menu - Secondary & Destructive Actions */}
96
+ <div className="relative" ref={menuRef}>
97
+ <button
98
+ onClick={() => setIsMenuOpen(!isMenuOpen)}
99
+ className="p-1.5 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-md transition-colors dark:text-gray-400 dark:hover:text-gray-100 dark:hover:bg-gray-700"
100
+ title="More Actions"
101
+ aria-label="More Actions"
102
+ aria-expanded={isMenuOpen}
103
+ >
104
+ <MoreVertical className="h-4 w-4" />
105
+ </button>
106
+
107
+ {isMenuOpen && (
108
+ <div className="absolute right-0 mt-1 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 z-50 py-1">
109
+ {/* Approval Actions - Only show when pending */}
110
+ {hasApproval && isPending && (
111
+ <>
112
+ {onApprove && (
113
+ <button
114
+ onClick={() => {
115
+ onApprove(row);
116
+ setIsMenuOpen(false);
117
+ }}
118
+ className="w-full flex items-center gap-3 px-4 py-2 text-sm text-emerald-700 hover:bg-emerald-50 dark:text-emerald-400 dark:hover:bg-emerald-950/30"
119
+ >
120
+ <CheckCircle className="h-4 w-4" />
121
+ <span>Approve</span>
122
+ </button>
123
+ )}
124
+ {onReject && (
125
+ <button
126
+ onClick={() => {
127
+ onReject(row);
128
+ setIsMenuOpen(false);
129
+ }}
130
+ className="w-full flex items-center gap-3 px-4 py-2 text-sm text-rose-700 hover:bg-rose-50 dark:text-rose-400 dark:hover:bg-rose-950/30"
131
+ >
132
+ <XCircle className="h-4 w-4" />
133
+ <span>Reject</span>
134
+ </button>
135
+ )}
136
+ <div className="border-t border-gray-200 dark:border-gray-700 my-1" />
137
+ </>
138
+ )}
139
+
140
+ {/* View History */}
141
+ {hasApproval && onViewHistory && (
142
+ <>
143
+ <button
144
+ onClick={() => {
145
+ onViewHistory(row);
146
+ setIsMenuOpen(false);
147
+ }}
148
+ className="w-full flex items-center gap-3 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-700"
149
+ >
150
+ <History className="h-4 w-4" />
151
+ <span>View History</span>
152
+ </button>
153
+ <div className="border-t border-gray-200 dark:border-gray-700 my-1" />
154
+ </>
155
+ )}
156
+
157
+ {/* Toggle Status */}
158
+ {onToggle && (
159
+ <button
160
+ onClick={() => {
161
+ onToggle(row);
162
+ setIsMenuOpen(false);
163
+ }}
164
+ className="w-full flex items-center gap-3 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-700"
165
+ >
166
+ <Power className="h-4 w-4" />
167
+ <div className="flex flex-col items-start">
168
+ <span>Toggle Status</span>
169
+ <span className="text-xs text-gray-500 dark:text-gray-400">
170
+ {row.is_active ? 'Deactivate' : 'Activate'}
171
+ </span>
172
+ </div>
173
+ </button>
174
+ )}
175
+
176
+ {/* Delete - Always last, always red */}
177
+ {onDelete && (
178
+ <>
179
+ <div className="border-t border-gray-200 dark:border-gray-700 my-1" />
180
+ <button
181
+ onClick={() => {
182
+ onDelete(row);
183
+ setIsMenuOpen(false);
184
+ }}
185
+ className="w-full flex items-center gap-3 px-4 py-2 text-sm text-rose-700 hover:bg-rose-50 dark:text-rose-400 dark:hover:bg-rose-950/30"
186
+ >
187
+ <Trash2 className="h-4 w-4" />
188
+ <span>Delete</span>
189
+ </button>
190
+ </>
191
+ )}
192
+ </div>
193
+ )}
194
+ </div>
195
+ </div>
196
+ );
197
+ }
198
+
199
+ RowActionsCell.propTypes = {
200
+ row: PropTypes.object.isRequired,
201
+ onView: PropTypes.func,
202
+ onEdit: PropTypes.func,
203
+ editPath: PropTypes.string,
204
+ onToggle: PropTypes.func,
205
+ onDelete: PropTypes.func,
206
+ onApprove: PropTypes.func,
207
+ onReject: PropTypes.func,
208
+ onViewHistory: PropTypes.func,
209
+ hasApproval: PropTypes.bool,
210
+ };
211
+
212
+ export default RowActionsCell;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @vasuzex/react - DataTable Cell Components
3
+ * Reusable cell renderers for common patterns
4
+ */
5
+
6
+ export { ApprovalStatusCell } from './ApprovalStatusCell.jsx';
7
+ export { RowActionsCell } from './RowActionsCell.jsx';
8
+ export { default as ApprovalStatusCellDefault } from './ApprovalStatusCell.jsx';
9
+ export { default as RowActionsCellDefault } from './RowActionsCell.jsx';
@@ -16,3 +16,6 @@ export {
16
16
  createViewClickHandler,
17
17
  createDeleteClickHandler
18
18
  } from './ActionDefaults.jsx';
19
+
20
+ // Cell Components - Reusable cell renderers
21
+ export { ApprovalStatusCell, RowActionsCell } from './CellComponents/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vasuzex",
3
- "version": "2.1.16",
3
+ "version": "2.1.18",
4
4
  "description": "Laravel-inspired framework for Node.js monorepos - V2 with optimized dependencies",
5
5
  "type": "module",
6
6
  "main": "./framework/index.js",
@@ -108,13 +108,14 @@
108
108
  "express-rate-limit": "^8.2.1",
109
109
  "firebase-admin": "^13.6.0",
110
110
  "fs-extra": "^11.3.2",
111
- "guruorm": "^2.0.16",
111
+ "guruorm": "^2.0.17",
112
112
  "helmet": "^8.1.0",
113
113
  "inquirer": "^9.3.8",
114
114
  "ip2location-nodejs": "^9.7.0",
115
115
  "joi": "^17.13.3",
116
116
  "jose": "^6.1.3",
117
117
  "jsonwebtoken": "^9.0.3",
118
+ "lucide-react": "^0.553.0",
118
119
  "maxmind": "^5.0.1",
119
120
  "multer": "^2.0.2",
120
121
  "node-plop": "^0.32.3",
@@ -1,201 +0,0 @@
1
- # 🚨 STRICT LOGGING POLICY - MANDATORY
2
-
3
- ## ❌ FORBIDDEN - NEVER USE THESE
4
-
5
- ```javascript
6
- // ❌ STRICTLY FORBIDDEN - DO NOT USE!
7
- console.log()
8
- console.warn()
9
- console.error()
10
- console.info()
11
- console.debug()
12
- ```
13
-
14
- **VIOLATION OF THIS RULE WILL BE REJECTED IMMEDIATELY!**
15
-
16
- ---
17
-
18
- ## ✅ CORRECT LOGGING METHODS
19
-
20
- ### Backend (API) - Use Vasuzex Log Facade
21
-
22
- ```javascript
23
- import { Log } from 'vasuzex';
24
-
25
- // Info logging
26
- Log.info('User logged in', { userId: user.id });
27
-
28
- // Warning logging
29
- Log.warning('Rate limit approaching', { ip: req.ip, count: 95 });
30
-
31
- // Error logging
32
- Log.error('Database connection failed', { error: err.message });
33
-
34
- // Debug logging (development only)
35
- Log.debug('Processing order', { orderId: 123, items: 5 });
36
-
37
- // Critical errors
38
- Log.critical('Payment gateway down', { gateway: 'razorpay' });
39
-
40
- // Alerts (requires immediate action)
41
- Log.alert('Disk space critical', { available: '5%' });
42
- ```
43
-
44
- ### Frontend (Web) - Use Custom Logger Utility
45
-
46
- ```javascript
47
- import { logger } from '@/utils/logger';
48
-
49
- // Info logging (development only)
50
- logger.info('Config loaded', { apiUrl, mediaUrl });
51
-
52
- // Warning logging
53
- logger.warning('API rate limit warning', { remaining: 10 });
54
-
55
- // Error logging (always logged)
56
- logger.error('Failed to fetch data', error);
57
-
58
- // Debug logging (development only)
59
- logger.debug('Component mounted', { props });
60
- ```
61
-
62
- ---
63
-
64
- ## 📁 Logger Implementation
65
-
66
- ### Backend: Vasuzex Log Facade
67
-
68
- **Location:** `vasuzex-v2/framework/Support/Facades/Log.js`
69
-
70
- **Methods:**
71
- - `Log.emergency()` - System unusable
72
- - `Log.alert()` - Immediate action required
73
- - `Log.critical()` - Critical conditions
74
- - `Log.error()` - Runtime errors
75
- - `Log.warning()` - Exceptional but not errors
76
- - `Log.notice()` - Normal but significant
77
- - `Log.info()` - Interesting events
78
- - `Log.debug()` - Debug information
79
-
80
- **Configuration:** `config/logging.cjs`
81
-
82
- ### Frontend: Custom Logger Utility
83
-
84
- **Location:** `apps/customer/web/src/utils/logger.js`
85
-
86
- **Features:**
87
- - Automatic timestamp
88
- - Context serialization
89
- - Development-only info/debug logs
90
- - Always-on error logs
91
- - Prefix: `[neasto]`
92
-
93
- **Methods:**
94
- - `logger.info(message, context)` - Development only
95
- - `logger.warning(message, context)` - Development/Test
96
- - `logger.error(message, error)` - Always logged
97
- - `logger.debug(message, data)` - Development only
98
-
99
- ---
100
-
101
- ## 🔍 Examples
102
-
103
- ### ✅ CORRECT
104
-
105
- ```javascript
106
- // Backend
107
- import { Log } from 'vasuzex';
108
-
109
- async function sendOTP(phone) {
110
- Log.info(`OTP sent to ${phone}`);
111
- }
112
-
113
- async function processPayment(orderId) {
114
- try {
115
- // ... payment logic
116
- Log.info('Payment processed', { orderId, amount });
117
- } catch (error) {
118
- Log.error('Payment failed', { orderId, error: error.message });
119
- throw error;
120
- }
121
- }
122
-
123
- // Frontend
124
- import { logger } from '@/utils/logger';
125
-
126
- function LoginForm() {
127
- const handleLogin = async () => {
128
- try {
129
- logger.debug('Login attempt', { phone });
130
- const result = await authService.login(phone);
131
- logger.info('Login successful');
132
- } catch (error) {
133
- logger.error('Login failed', error);
134
- }
135
- };
136
- }
137
- ```
138
-
139
- ### ❌ WRONG
140
-
141
- ```javascript
142
- // ❌ NEVER DO THIS!
143
- console.log('User logged in');
144
- console.error('Failed to process');
145
- console.warn('Rate limit warning');
146
-
147
- // ❌ NEVER DO THIS IN PRODUCTION CODE!
148
- if (isDevelopment) {
149
- console.log('Debug info'); // Still wrong! Use logger
150
- }
151
- ```
152
-
153
- ---
154
-
155
- ## 📋 Migration Checklist
156
-
157
- When adding new code:
158
-
159
- - [ ] Import `Log` from `vasuzex` (backend)
160
- - [ ] Import `logger` from `@/utils/logger` (frontend)
161
- - [ ] NO direct console.* calls anywhere
162
- - [ ] Use appropriate log level (info/warning/error/debug)
163
- - [ ] Include context objects for debugging
164
- - [ ] Test logging in development mode
165
-
166
- ---
167
-
168
- ## 🔧 Current Status
169
-
170
- ### Backend Files Using Log Facade ✅
171
-
172
- - `apps/customer/api/src/services/AuthService.js`
173
- - `apps/customer/api/src/services/OrderModificationService.js`
174
-
175
- ### Frontend Files Using Logger ✅
176
-
177
- - `apps/customer/web/src/hooks/useAuth.js`
178
- - `apps/customer/web/src/components/auth/LoginForm.jsx`
179
- - `apps/customer/web/src/App.jsx`
180
- - `apps/customer/web/src/lib/AppConfigProvider.jsx`
181
-
182
- ### Cleaned Files (No Logging) ✅
183
-
184
- - `apps/customer/web/src/main.jsx`
185
- - `apps/customer/web/src/lib/api-client.js`
186
-
187
- ---
188
-
189
- ## ⚠️ REMEMBER
190
-
191
- **NEVER write `console.log`, `console.warn`, or `console.error` in any file!**
192
-
193
- **ALWAYS use:**
194
- - Backend: `Log.info()`, `Log.error()`, `Log.warning()`, `Log.debug()`
195
- - Frontend: `logger.info()`, `logger.error()`, `logger.warning()`, `logger.debug()`
196
-
197
- **This is not a suggestion - it's a strict requirement!**
198
-
199
- ---
200
-
201
- Last Updated: 2025-12-10