fernando-bold commited on
Commit
6decb61
·
verified ·
1 Parent(s): 637ffd6

'use client'

Browse files

import React, { useState } from 'react'
import { Button } from "@medusajs/ui"
import { useCreateSolarAffiliate } from '../../../lib/hooks/solar-affiliates'
import { useCompany } from '../../../lib/hooks/companies'

interface SolarAffiliateRegistrationFormProps {
onSuccess?: () => void
onCancel?: () => void
}

const SolarAffiliateRegistrationForm: React.FC<SolarAffiliateRegistrationFormProps> = ({
onSuccess,
onCancel
}) => {
const [formData, setFormData] = useState({
company_id: '',
affiliate_type: 'REFERRAL_PARTNER',
affiliate_tier: 'BRONZE',
commission_rate: 5,
referral_code: '',
total_referrals: 0,
successful_referrals: 0,
total_earnings: '',
pending_earnings: '',
average_conversion_rate: 0,
traffic_sources: [] as string[],
marketing_channels: [] as string[],
content_types: [] as string[],
target_audience: [] as string[],
marketing_materials_access: false,
performance_bonus_eligible: false,
custom_promo_codes: [] as string[],
commission_structure: 'percentage',
payment_method: '',
payment_frequency: 'monthly',
tax_id: '',
marketing_support_level: 'basic',
training_completed: false,
certification_level: 0,
preferred_communication: [] as string[],
})

const [currentStep, setCurrentStep] = useState(1)
const totalSteps = 3

const { mutateAsync: createAffiliate, isPending } = useCreateSolarAffiliate()
const { data: companyData } = useCompany({}) // Get company data

const handleInputChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>
) => {
const { name, value, type } = e.target
if (type === 'checkbox') {
const checkbox = e.target as HTMLInputElement
setFormData(prev => ({ ...prev, [name]: checkbox.checked }))
} else {
setFormData(prev => ({ ...prev, [name]: value }))
}
}

const handleArrayChange = (name: string, value: string) => {
setFormData(prev => {
const currentArray = (prev as any)[name] as string[]
const newArray = currentArray.includes(value)
? currentArray.filter(item => item !== value)
: [...currentArray, value]
return { ...prev, [name]: newArray }
})
}

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()

try {
// In a real app, you would first create or get the company
// For now, we'll simulate getting a company ID
const company_id = companyData?.companies?.[0]?.id || 'comp_123'

await createAffiliate({
...formData,
company_id
})

onSuccess?.()
} catch (error) {
console.error('Error creating solar affiliate:', error)
alert('Erro ao registrar afiliado solar. Por favor, tente novamente.')
}
}

// Step 1: Basic Affiliate Information
const renderStep1 = () => (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Informações Básicas do Afiliado</h3>

<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-gray-700">Tipo de Afiliado *</label>
<select
name="affiliate_type"
value={formData.affiliate_type}
onChange={handleInputChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
>
<option value="REFERRAL_PARTNER">Parceiro de Referência</option>
<option value="INFLUENCER">Influenciador</option>
<option value="INDUSTRY_EXPERT">Especialista da Indústria</option>
<option value="YOUTUBE_CREATOR">Criador de Conteúdo (YouTube)</option>
<option value="BLOGGER">Blogueiro</option>
<option value="CONSULTANT">Consultor</option>
<option value="RETAILER">Revendedor</option>
</select>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Nível do Afiliado</label>
<select
name="affiliate_tier"
value={formData.affiliate_tier}
onChange={handleInputChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
>
<option value="BRONZE">Bronze</option>
<option value="SILVER">Prata</option>
<option value="GOLD">Ouro</option>
<option value="PLATINUM">Platina</option>
<option value="ELITE">Elite</option>
</select>
</div>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-gray-700">Taxa de Comissão (%)</label>
<input
type="number"
name="commission_rate"
value={formData.commission_rate}
onChange={handleInputChange}
min="0"
max="50"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Código de Referência</label>
<input
type="text"
name="referral_code"
value={formData.referral_code}
onChange={handleInputChange}
placeholder="ex: SOLARPARTNER123"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>

<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="text-sm font-medium text-gray-700">Total de Referências</label>
<input
type="number"
name="total_referrals"
value={formData.total_referrals}
onChange={handleInputChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Referências Bem-sucedidas</label>
<input
type="number"
name="successful_referrals"
value={formData.successful_referrals}
onChange={handleInputChange}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Taxa de Conversão Média (%)</label>
<input
type="number"
name="average_conversion_rate"
value={formData.average_conversion_rate}
onChange={handleInputChange}
min="0"
max="100"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="text-sm font-medium text-gray-700">Ganhos Totais</label>
<input
type="text"
name="total_earnings"
value={formData.total_earnings}
onChange={handleInputChange}
placeholder="ex: 5000.00"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Ganhos Pendentes</label>
<input
type="text"
name="pending_earnings"
value={formData.pending_earnings}
onChange={handleInputChange}
placeholder="ex: 500.00"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>
</div>
)

// Step 2: Marketing and Content Strategy
const renderStep2 = () => (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Marketing e Estratégia de Conteúdo</h3>

<div>
<label className="text-sm font-medium text-gray-700">Fontes de Tráfego</label>
<div className="mt-1 space-y-2">
{['organic', 'social', 'paid', 'email', 'referral', 'direct'].map((source) => (
<div key={source} className="flex items-center">
<input
id={`source-${source}`}
name="traffic_sources"
type="checkbox"
checked={formData.traffic_sources.includes(source)}
onChange={() => handleArrayChange('traffic_sources', source)}
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
<label htmlFor={`source-${source}`} className="ml-2 block text-sm text-gray-900 capitalize">
{source === 'organic' && 'Orgânico'}
{source === 'social' && 'Redes Sociais'}
{source === 'paid' && 'Pago'}
{source === 'email' && 'Email'}
{source === 'referral' && 'Referência'}
{source === 'direct' && 'Direto'}
</label>
</div>
))}
</div>
</div>

<div>
<label className="text-sm font-medium text-gray-700">Canais de Marketing</label>
<div className="mt-1 space-y-2">
{['facebook', 'instagram', 'linkedin', 'youtube', 'tiktok', 'twitter', 'whatsapp', 'blog'].map((channel) => (
<div key={channel} className="flex items-center">
<input
id={`channel-${channel}`}
name="marketing_channels"
type="checkbox"
checked={formData.marketing_channels.includes(channel)}
onChange={() => handleArrayChange('marketing_channels', channel)}
className="h-4 w-4 rounded bord

Files changed (1) hide show
  1. components/solar-affiliate-form.js +268 -0
components/solar-affiliate-form.js ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```javascript
2
+ class CustomSolarAffiliateForm extends HTMLElement {
3
+ constructor() {
4
+ super();
5
+ this.currentStep = 1;
6
+ this.totalSteps = 3;
7
+ this.formData = {
8
+ company_id: '',
9
+ affiliate_type: 'REFERRAL_PARTNER',
10
+ affiliate_tier: 'BRONZE',
11
+ commission_rate: 5,
12
+ referral_code: '',
13
+ total_referrals: 0,
14
+ successful_referrals: 0,
15
+ total_earnings: '',
16
+ pending_earnings: '',
17
+ average_conversion_rate: 0,
18
+ traffic_sources: [],
19
+ marketing_channels: [],
20
+ content_types: [],
21
+ target_audience: [],
22
+ marketing_materials_access: false,
23
+ performance_bonus_eligible: false,
24
+ custom_promo_codes: [],
25
+ commission_structure: 'percentage',
26
+ payment_method: '',
27
+ payment_frequency: 'monthly',
28
+ tax_id: '',
29
+ marketing_support_level: 'basic',
30
+ training_completed: false,
31
+ certification_level: 0,
32
+ preferred_communication: [],
33
+ };
34
+ }
35
+
36
+ connectedCallback() {
37
+ this.attachShadow({ mode: 'open' });
38
+ this.render();
39
+ }
40
+
41
+ handleInputChange(e) {
42
+ const { name, value, type, checked } = e.target;
43
+ if (type === 'checkbox') {
44
+ this.formData[name] = checked;
45
+ } else {
46
+ this.formData[name] = value;
47
+ }
48
+ this.render();
49
+ }
50
+
51
+ handleArrayChange(name, value) {
52
+ const currentArray = this.formData[name];
53
+ const newArray = currentArray.includes(value)
54
+ ? currentArray.filter(item => item !== value)
55
+ : [...currentArray, value];
56
+ this.formData[name] = newArray;
57
+ this.render();
58
+ }
59
+
60
+ nextStep() {
61
+ if (this.currentStep < this.totalSteps) {
62
+ this.currentStep++;
63
+ this.render();
64
+ }
65
+ }
66
+
67
+ prevStep() {
68
+ if (this.currentStep > 1) {
69
+ this.currentStep--;
70
+ this.render();
71
+ }
72
+ }
73
+
74
+ renderStep1() {
75
+ return `
76
+ <div class="space-y-4">
77
+ <h3 class="text-lg font-semibold">Informações Básicas do Afiliado</h3>
78
+
79
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
80
+ <div>
81
+ <label class="text-sm font-medium text-gray-700">Tipo de Afiliado *</label>
82
+ <select
83
+ name="affiliate_type"
84
+ value="${this.formData.affiliate_type}"
85
+ onchange="this.getRootNode().host.handleInputChange(event)"
86
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
87
+ >
88
+ <option value="REFERRAL_PARTNER">Parceiro de Referência</option>
89
+ <option value="INFLUENCER">Influenciador</option>
90
+ <option value="INDUSTRY_EXPERT">Especialista da Indústria</option>
91
+ <option value="YOUTUBE_CREATOR">Criador de Conteúdo (YouTube)</option>
92
+ <option value="BLOGGER">Blogueiro</option>
93
+ <option value="CONSULTANT">Consultor</option>
94
+ <option value="RETAILER">Revendedor</option>
95
+ </select>
96
+ </div>
97
+
98
+ <div>
99
+ <label class="text-sm font-medium text-gray-700">Nível do Afiliado</label>
100
+ <select
101
+ name="affiliate_tier"
102
+ value="${this.formData.affiliate_tier}"
103
+ onchange="this.getRootNode().host.handleInputChange(event)"
104
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
105
+ >
106
+ <option value="BRONZE">Bronze</option>
107
+ <option value="SILVER">Prata</option>
108
+ <option value="GOLD">Ouro</option>
109
+ <option value="PLATINUM">Platina</option>
110
+ <option value="ELITE">Elite</option>
111
+ </select>
112
+ </div>
113
+ </div>
114
+
115
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
116
+ <div>
117
+ <label class="text-sm font-medium text-gray-700">Taxa de Comissão (%)</label>
118
+ <input
119
+ type="number"
120
+ name="commission_rate"
121
+ value="${this.formData.commission_rate}"
122
+ onchange="this.getRootNode().host.handleInputChange(event)"
123
+ min="0"
124
+ max="50"
125
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
126
+ />
127
+ </div>
128
+
129
+ <div>
130
+ <label class="text-sm font-medium text-gray-700">Código de Referência</label>
131
+ <input
132
+ type="text"
133
+ name="referral_code"
134
+ value="${this.formData.referral_code}"
135
+ onchange="this.getRootNode().host.handleInputChange(event)"
136
+ placeholder="ex: SOLARPARTNER123"
137
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
138
+ />
139
+ </div>
140
+ </div>
141
+
142
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
143
+ <div>
144
+ <label class="text-sm font-medium text-gray-700">Total de Referências</label>
145
+ <input
146
+ type="number"
147
+ name="total_referrals"
148
+ value="${this.formData.total_referrals}"
149
+ onchange="this.getRootNode().host.handleInputChange(event)"
150
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
151
+ />
152
+ </div>
153
+
154
+ <div>
155
+ <label class="text-sm font-medium text-gray-700">Referências Bem-sucedidas</label>
156
+ <input
157
+ type="number"
158
+ name="successful_referrals"
159
+ value="${this.formData.successful_referrals}"
160
+ onchange="this.getRootNode().host.handleInputChange(event)"
161
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
162
+ />
163
+ </div>
164
+
165
+ <div>
166
+ <label class="text-sm font-medium text-gray-700">Taxa de Conversão Média (%)</label>
167
+ <input
168
+ type="number"
169
+ name="average_conversion_rate"
170
+ value="${this.formData.average_conversion_rate}"
171
+ onchange="this.getRootNode().host.handleInputChange(event)"
172
+ min="0"
173
+ max="100"
174
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
175
+ />
176
+ </div>
177
+ </div>
178
+
179
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
180
+ <div>
181
+ <label class="text-sm font-medium text-gray-700">Ganhos Totais</label>
182
+ <input
183
+ type="text"
184
+ name="total_earnings"
185
+ value="${this.formData.total_earnings}"
186
+ onchange="this.getRootNode().host.handleInputChange(event)"
187
+ placeholder="ex: 5000.00"
188
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
189
+ />
190
+ </div>
191
+
192
+ <div>
193
+ <label class="text-sm font-medium text-gray-700">Ganhos Pendentes</label>
194
+ <input
195
+ type="text"
196
+ name="pending_earnings"
197
+ value="${this.formData.pending_earnings}"
198
+ onchange="this.getRootNode().host.handleInputChange(event)"
199
+ placeholder="ex: 500.00"
200
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
201
+ />
202
+ </div>
203
+ </div>
204
+ </div>
205
+ `;
206
+ }
207
+
208
+ renderStep2() {
209
+ return `
210
+ <div class="space-y-4">
211
+ <h3 class="text-lg font-semibold">Marketing e Estratégia de Conteúdo</h3>
212
+
213
+ <div>
214
+ <label class="text-sm font-medium text-gray-700">Fontes de Tráfego</label>
215
+ <div class="mt-1 space-y-2">
216
+ ${['organic', 'social', 'paid', 'email', 'referral', 'direct'].map(source => `
217
+ <div key="${source}" class="flex items-center">
218
+ <input
219
+ id="source-${source}"
220
+ name="traffic_sources"
221
+ type="checkbox"
222
+ ${this.formData.traffic_sources.includes(source) ? 'checked' : ''}
223
+ onchange="this.getRootNode().host.handleArrayChange('traffic_sources', '${source}')"
224
+ class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
225
+ />
226
+ <label for="source-${source}" class="ml-2 block text-sm text-gray-900 capitalize">
227
+ ${source === 'organic' ? 'Orgânico' :
228
+ source === 'social' ? 'Redes Sociais' :
229
+ source === 'paid' ? 'Pago' :
230
+ source === 'email' ? 'Email' :
231
+ source === 'referral' ? 'Referência' : 'Direto'}
232
+ </label>
233
+ </div>
234
+ `).join('')}
235
+ </div>
236
+ </div>
237
+
238
+ <div>
239
+ <label class="text-sm font-medium text-gray-700">Canais de Marketing</label>
240
+ <div class="mt-1 space-y-2">
241
+ ${['facebook', 'instagram', 'linkedin', 'youtube', 'tiktok', 'twitter', 'whatsapp', 'blog'].map(channel => `
242
+ <div key="${channel}" class="flex items-center">
243
+ <input
244
+ id="channel-${channel}"
245
+ name="marketing_channels"
246
+ type="checkbox"
247
+ ${this.formData.marketing_channels.includes(channel) ? 'checked' : ''}
248
+ onchange="this.getRootNode().host.handleArrayChange('marketing_channels', '${channel}')"
249
+ class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
250
+ />
251
+ <label for="channel-${channel}" class="ml-2 block text-sm text-gray-900 capitalize">
252
+ ${channel}
253
+ </label>
254
+ </div>
255
+ `).join('')}
256
+ </div>
257
+ </div>
258
+
259
+ <div>
260
+ <label class="text-sm font-medium text-gray-700">Tipos de Conteúdo</label>
261
+ <div class="mt-1 space-y-2">
262
+ ${['blog', 'video', 'testimonial', 'comparison', 'review', 'tutorial', 'case_study'].map(content => `
263
+ <div key="${content}" class="flex items-center">
264
+ <input
265
+ id="content-${content}"
266
+ name="content_types"
267
+ type="checkbox"
268
+ ${this.formData.content