@visns-studio/visns-components 5.13.8 → 5.13.10

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,213 @@
1
+ /* Branding Profile Company Info Styles */
2
+ .branding-company-info-display,
3
+ .branding-company-info-editor {
4
+ background: var(--tertiary-color, white);
5
+ border-radius: 8px;
6
+ padding: 1.5rem;
7
+ border: 1px solid var(--paragraph-color, #e2e8f0);
8
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
9
+ margin-bottom: 1.5rem;
10
+ }
11
+
12
+ .branding-company-info-header {
13
+ margin-bottom: 1.5rem;
14
+ }
15
+
16
+ .branding-company-info-title {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 0.5rem;
20
+ margin-bottom: 0.5rem;
21
+ }
22
+
23
+ .branding-company-info-title h4 {
24
+ margin: 0;
25
+ font-size: 1.125rem;
26
+ font-weight: 600;
27
+ color: var(--header-color, #1f2937);
28
+ }
29
+
30
+ .branding-company-info-title svg {
31
+ color: var(--primary-color, #3cbf7d);
32
+ }
33
+
34
+ .branding-company-info-description {
35
+ color: var(--paragraph-color, #6b7280);
36
+ margin: 0;
37
+ font-size: 0.875rem;
38
+ }
39
+
40
+ .branding-company-info-edit-btn {
41
+ background: var(--primary-color, #3cbf7d);
42
+ color: white;
43
+ border: none;
44
+ border-radius: 4px;
45
+ padding: 0.5rem 1rem;
46
+ font-size: 0.875rem;
47
+ font-weight: 500;
48
+ cursor: pointer;
49
+ transition: all 0.2s;
50
+ }
51
+
52
+ .branding-company-info-edit-btn:hover {
53
+ background: var(--header-color, #1b3933);
54
+ }
55
+
56
+ /* Display Mode */
57
+ .branding-company-info-content {
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: 0.75rem;
61
+ }
62
+
63
+ .branding-company-info-item {
64
+ display: flex;
65
+ gap: 0.5rem;
66
+ font-size: 0.875rem;
67
+ line-height: 1.4;
68
+ }
69
+
70
+ .branding-company-info-item strong {
71
+ color: var(--header-color, #374151);
72
+ min-width: 80px;
73
+ flex-shrink: 0;
74
+ }
75
+
76
+ .branding-company-info-empty {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 0.5rem;
80
+ padding: 1rem;
81
+ background: var(--bg-color, #f9fafb);
82
+ border-radius: 6px;
83
+ border: 1px dashed var(--paragraph-color, #d1d5db);
84
+ color: var(--paragraph-color, #6b7280);
85
+ font-size: 0.875rem;
86
+ }
87
+
88
+ .branding-company-info-empty svg {
89
+ color: var(--paragraph-color, #9ca3af);
90
+ }
91
+
92
+ .branding-company-info-empty p {
93
+ margin: 0;
94
+ }
95
+
96
+ /* Edit Mode */
97
+ .branding-company-info-form {
98
+ display: flex;
99
+ flex-direction: column;
100
+ gap: 1.25rem;
101
+ }
102
+
103
+ .branding-company-info-field {
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: 0.5rem;
107
+ }
108
+
109
+ .branding-company-info-field label {
110
+ font-weight: 600;
111
+ color: var(--header-color, #374151);
112
+ font-size: 0.875rem;
113
+ }
114
+
115
+ .branding-company-info-field input,
116
+ .branding-company-info-field textarea {
117
+ padding: 0.75rem;
118
+ border: 1px solid var(--paragraph-color, #d1d5db);
119
+ border-radius: 6px;
120
+ font-size: 0.875rem;
121
+ transition: all 0.2s;
122
+ background: var(--tertiary-color, white);
123
+ }
124
+
125
+ .branding-company-info-field input:focus,
126
+ .branding-company-info-field textarea:focus {
127
+ outline: none;
128
+ border-color: var(--primary-color, #3cbf7d);
129
+ box-shadow: 0 0 0 3px rgba(60, 191, 125, 0.1);
130
+ }
131
+
132
+ .branding-company-info-field textarea {
133
+ resize: vertical;
134
+ min-height: 80px;
135
+ }
136
+
137
+ .branding-company-info-field input::placeholder,
138
+ .branding-company-info-field textarea::placeholder {
139
+ color: var(--paragraph-color, #9ca3af);
140
+ }
141
+
142
+ /* Actions */
143
+ .branding-company-info-actions {
144
+ display: flex;
145
+ align-items: center;
146
+ justify-content: flex-end;
147
+ gap: 0.75rem;
148
+ margin-top: 1.5rem;
149
+ padding-top: 1.5rem;
150
+ border-top: 1px solid var(--paragraph-color, #e5e7eb);
151
+ }
152
+
153
+ .branding-company-info-btn {
154
+ display: inline-flex;
155
+ align-items: center;
156
+ gap: 0.5rem;
157
+ padding: 0.75rem 1.25rem;
158
+ font-size: 0.875rem;
159
+ font-weight: 600;
160
+ border-radius: 6px;
161
+ cursor: pointer;
162
+ transition: all 0.2s;
163
+ border: none;
164
+ text-decoration: none;
165
+ }
166
+
167
+ .branding-company-info-btn:disabled {
168
+ opacity: 0.6;
169
+ cursor: not-allowed;
170
+ }
171
+
172
+ .branding-company-info-btn.secondary {
173
+ background: var(--tertiary-color, white);
174
+ color: var(--paragraph-color, #6b7280);
175
+ border: 1px solid var(--paragraph-color, #d1d5db);
176
+ }
177
+
178
+ .branding-company-info-btn.secondary:hover:not(:disabled) {
179
+ background: var(--bg-color, #f9fafb);
180
+ border-color: var(--paragraph-color, #9ca3af);
181
+ }
182
+
183
+ .branding-company-info-btn.primary {
184
+ background: var(--primary-color, #3cbf7d);
185
+ color: white;
186
+ border: 1px solid var(--primary-color, #3cbf7d);
187
+ box-shadow: 0 2px 4px rgba(60, 191, 125, 0.2);
188
+ }
189
+
190
+ .branding-company-info-btn.primary:hover:not(:disabled) {
191
+ background: var(--header-color, #1b3933);
192
+ border-color: var(--header-color, #1b3933);
193
+ box-shadow: 0 4px 8px rgba(27, 57, 51, 0.3);
194
+ transform: translateY(-1px);
195
+ }
196
+
197
+ /* Responsive Design */
198
+ @media (max-width: 768px) {
199
+ .branding-company-info-display,
200
+ .branding-company-info-editor {
201
+ padding: 1rem;
202
+ }
203
+
204
+ .branding-company-info-actions {
205
+ flex-direction: column-reverse;
206
+ gap: 0.5rem;
207
+ }
208
+
209
+ .branding-company-info-btn {
210
+ width: 100%;
211
+ justify-content: center;
212
+ }
213
+ }
@@ -0,0 +1,194 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Building, Save, X, Info } from 'lucide-react';
3
+ import { toast } from 'react-toastify';
4
+ import './BrandingProfileCompanyInfo.css';
5
+
6
+ const BrandingProfileCompanyInfo = ({
7
+ brandingProfile,
8
+ onSave,
9
+ onCancel,
10
+ isEditing = false,
11
+ apiEndpoint = '/ajax/branding-profiles'
12
+ }) => {
13
+ const [companyInfo, setCompanyInfo] = useState({
14
+ address: '',
15
+ website: '',
16
+ phone: '',
17
+ abn: '',
18
+ ...brandingProfile?.company_info || {}
19
+ });
20
+
21
+ const [isLoading, setIsLoading] = useState(false);
22
+
23
+ const handleInputChange = (field, value) => {
24
+ setCompanyInfo(prev => ({
25
+ ...prev,
26
+ [field]: value
27
+ }));
28
+ };
29
+
30
+ const handleSave = async () => {
31
+ try {
32
+ setIsLoading(true);
33
+
34
+ const response = await fetch(`${apiEndpoint}/${brandingProfile.id}`, {
35
+ method: 'PUT',
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
39
+ },
40
+ body: JSON.stringify({
41
+ ...brandingProfile,
42
+ company_info: companyInfo
43
+ })
44
+ });
45
+
46
+ if (response.ok) {
47
+ const data = await response.json();
48
+ toast.success('Company information updated successfully');
49
+ if (onSave) {
50
+ onSave({
51
+ ...brandingProfile,
52
+ company_info: companyInfo
53
+ });
54
+ }
55
+ } else {
56
+ throw new Error('Failed to update company information');
57
+ }
58
+ } catch (error) {
59
+ console.error('Error updating company info:', error);
60
+ toast.error('Failed to update company information');
61
+ } finally {
62
+ setIsLoading(false);
63
+ }
64
+ };
65
+
66
+ if (!isEditing) {
67
+ return (
68
+ <div className="branding-company-info-display">
69
+ <div className="branding-company-info-header">
70
+ <div className="branding-company-info-title">
71
+ <Building size={20} />
72
+ <h4>Company Information</h4>
73
+ </div>
74
+ <button
75
+ onClick={() => onSave && onSave(null)}
76
+ className="branding-company-info-edit-btn"
77
+ >
78
+ Edit
79
+ </button>
80
+ </div>
81
+
82
+ <div className="branding-company-info-content">
83
+ {companyInfo.address && (
84
+ <div className="branding-company-info-item">
85
+ <strong>Address:</strong> {companyInfo.address}
86
+ </div>
87
+ )}
88
+ {companyInfo.website && (
89
+ <div className="branding-company-info-item">
90
+ <strong>Website:</strong> {companyInfo.website}
91
+ </div>
92
+ )}
93
+ {companyInfo.phone && (
94
+ <div className="branding-company-info-item">
95
+ <strong>Phone:</strong> {companyInfo.phone}
96
+ </div>
97
+ )}
98
+ {companyInfo.abn && (
99
+ <div className="branding-company-info-item">
100
+ <strong>ABN:</strong> {companyInfo.abn}
101
+ </div>
102
+ )}
103
+ {!companyInfo.address && !companyInfo.website && !companyInfo.phone && !companyInfo.abn && (
104
+ <div className="branding-company-info-empty">
105
+ <Info size={16} />
106
+ <p>No company information added yet. Click Edit to add details.</p>
107
+ </div>
108
+ )}
109
+ </div>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ return (
115
+ <div className="branding-company-info-editor">
116
+ <div className="branding-company-info-header">
117
+ <div className="branding-company-info-title">
118
+ <Building size={20} />
119
+ <h4>Edit Company Information</h4>
120
+ </div>
121
+ <p className="branding-company-info-description">
122
+ This information will be used in proposal headers and other branded documents.
123
+ </p>
124
+ </div>
125
+
126
+ <div className="branding-company-info-form">
127
+ <div className="branding-company-info-field">
128
+ <label htmlFor="company-address">Company Address</label>
129
+ <textarea
130
+ id="company-address"
131
+ value={companyInfo.address}
132
+ onChange={(e) => handleInputChange('address', e.target.value)}
133
+ placeholder="Enter full company address"
134
+ rows={3}
135
+ />
136
+ </div>
137
+
138
+ <div className="branding-company-info-field">
139
+ <label htmlFor="company-website">Website</label>
140
+ <input
141
+ type="url"
142
+ id="company-website"
143
+ value={companyInfo.website}
144
+ onChange={(e) => handleInputChange('website', e.target.value)}
145
+ placeholder="https://www.yourcompany.com"
146
+ />
147
+ </div>
148
+
149
+ <div className="branding-company-info-field">
150
+ <label htmlFor="company-phone">Phone Number</label>
151
+ <input
152
+ type="tel"
153
+ id="company-phone"
154
+ value={companyInfo.phone}
155
+ onChange={(e) => handleInputChange('phone', e.target.value)}
156
+ placeholder="(02) 1234 5678"
157
+ />
158
+ </div>
159
+
160
+ <div className="branding-company-info-field">
161
+ <label htmlFor="company-abn">ABN</label>
162
+ <input
163
+ type="text"
164
+ id="company-abn"
165
+ value={companyInfo.abn}
166
+ onChange={(e) => handleInputChange('abn', e.target.value)}
167
+ placeholder="12 345 678 901"
168
+ />
169
+ </div>
170
+ </div>
171
+
172
+ <div className="branding-company-info-actions">
173
+ <button
174
+ onClick={onCancel}
175
+ className="branding-company-info-btn secondary"
176
+ disabled={isLoading}
177
+ >
178
+ <X size={16} />
179
+ Cancel
180
+ </button>
181
+ <button
182
+ onClick={handleSave}
183
+ className="branding-company-info-btn primary"
184
+ disabled={isLoading}
185
+ >
186
+ <Save size={16} />
187
+ {isLoading ? 'Saving...' : 'Save Company Info'}
188
+ </button>
189
+ </div>
190
+ </div>
191
+ );
192
+ };
193
+
194
+ export default BrandingProfileCompanyInfo;