11"use client" ;
22
3- import { useEffect , useState } from "react" ;
3+ import { useCallback , useEffect , useState } from "react" ;
44import { toast } from "sonner" ;
55import { Button } from "@/components/ui/button" ;
6+ import { Checkbox } from "@/components/ui/checkbox" ;
67import {
78 Dialog ,
89 DialogContent ,
@@ -22,13 +23,21 @@ import {
2223 SelectValue ,
2324} from "@/components/ui/select" ;
2425import { Spinner } from "@/components/ui/spinner" ;
25- import { api , type Integration } from "@/lib/api-client" ;
26- import type { IntegrationType } from "@/lib/types/integration" ;
26+ import {
27+ api ,
28+ type Integration ,
29+ type IntegrationWithConfig ,
30+ } from "@/lib/api-client" ;
31+ import type {
32+ IntegrationConfig ,
33+ IntegrationType ,
34+ } from "@/lib/types/integration" ;
2735import {
2836 getIntegration ,
2937 getIntegrationLabels ,
3038 getSortedIntegrationTypes ,
3139} from "@/plugins" ;
40+ import { SendGridIntegrationSection } from "./sendgrid-integration-section" ;
3241import { Web3WalletSection } from "./web3-wallet-section" ;
3342
3443type IntegrationFormDialogProps = {
@@ -43,7 +52,7 @@ type IntegrationFormDialogProps = {
4352type IntegrationFormData = {
4453 name : string ;
4554 type : IntegrationType ;
46- config : Record < string , string > ;
55+ config : Record < string , string | boolean > ;
4756} ;
4857
4958// System integrations that don't have plugins
@@ -77,21 +86,70 @@ export function IntegrationFormDialog({
7786 config : { } ,
7887 } ) ;
7988
89+ const initializeConfigFromPlugin = useCallback (
90+ ( pluginType : IntegrationType ) : Record < string , string | boolean > => {
91+ const plugin = getIntegration ( pluginType ) ;
92+ const config : Record < string , string | boolean > = { } ;
93+ if ( plugin ?. formFields ) {
94+ for ( const field of plugin . formFields ) {
95+ if ( field . defaultValue !== undefined ) {
96+ config [ field . configKey ] = field . defaultValue as string | boolean ;
97+ }
98+ }
99+ }
100+ return config ;
101+ } ,
102+ [ ]
103+ ) ;
104+
105+ const initializeConfigFromIntegration = useCallback (
106+ (
107+ integrationData : Integration | IntegrationWithConfig
108+ ) : Record < string , string | boolean > => {
109+ const plugin = getIntegration ( integrationData . type ) ;
110+ const config : Record < string , string | boolean > = { } ;
111+
112+ if ( plugin ?. formFields && "config" in integrationData ) {
113+ const integrationConfig = integrationData . config as IntegrationConfig ;
114+ for ( const field of plugin . formFields ) {
115+ if ( integrationConfig [ field . configKey ] !== undefined ) {
116+ config [ field . configKey ] = integrationConfig [ field . configKey ] as
117+ | string
118+ | boolean ;
119+ } else if ( field . defaultValue !== undefined ) {
120+ config [ field . configKey ] = field . defaultValue as string | boolean ;
121+ }
122+ }
123+ }
124+
125+ return config ;
126+ } ,
127+ [ ]
128+ ) ;
129+
80130 useEffect ( ( ) => {
81131 if ( integration ) {
132+ const initialConfig = initializeConfigFromIntegration ( integration ) ;
82133 setFormData ( {
83134 name : integration . name ,
84135 type : integration . type ,
85- config : { } ,
136+ config : initialConfig ,
86137 } ) ;
87138 } else {
139+ const pluginType = preselectedType || "resend" ;
140+ const initialConfig = initializeConfigFromPlugin ( pluginType ) ;
88141 setFormData ( {
89142 name : "" ,
90- type : preselectedType || "resend" ,
91- config : { } ,
143+ type : pluginType ,
144+ config : initialConfig ,
92145 } ) ;
93146 }
94- } , [ integration , preselectedType ] ) ;
147+ } , [
148+ integration ,
149+ preselectedType ,
150+ initializeConfigFromIntegration ,
151+ initializeConfigFromPlugin ,
152+ ] ) ;
95153
96154 const handleSave = async ( ) => {
97155 try {
@@ -126,13 +184,96 @@ export function IntegrationFormDialog({
126184 }
127185 } ;
128186
129- const updateConfig = ( key : string , value : string ) => {
187+ const updateConfig = ( key : string , value : string | boolean ) => {
130188 setFormData ( {
131189 ...formData ,
132190 config : { ...formData . config , [ key ] : value } ,
133191 } ) ;
134192 } ;
135193
194+ const renderHelpText = (
195+ helpText ?: string ,
196+ helpLink ?: { text : string ; url : string }
197+ ) => {
198+ if ( ! ( helpText || helpLink ) ) {
199+ return null ;
200+ }
201+ return (
202+ < p className = "text-muted-foreground text-xs" >
203+ { helpText }
204+ { helpLink && (
205+ < a
206+ className = "underline hover:text-foreground"
207+ href = { helpLink . url }
208+ rel = "noopener noreferrer"
209+ target = "_blank"
210+ >
211+ { helpLink . text }
212+ </ a >
213+ ) }
214+ </ p >
215+ ) ;
216+ } ;
217+
218+ const renderCheckboxField = ( field : {
219+ id : string ;
220+ type : string ;
221+ label : string ;
222+ configKey : string ;
223+ defaultValue ?: string | boolean ;
224+ helpText ?: string ;
225+ helpLink ?: { text : string ; url : string } ;
226+ } ) => {
227+ let checkboxValue : string | boolean | undefined =
228+ formData . config [ field . configKey ] ;
229+ if ( checkboxValue === undefined ) {
230+ checkboxValue =
231+ field . defaultValue !== undefined ? field . defaultValue : true ;
232+ }
233+ const isChecked =
234+ typeof checkboxValue === "boolean"
235+ ? checkboxValue
236+ : checkboxValue === "true" ;
237+
238+ return (
239+ < div className = "flex items-center space-x-2" key = { field . id } >
240+ < Checkbox
241+ checked = { isChecked }
242+ id = { field . id }
243+ onCheckedChange = { ( checked ) =>
244+ updateConfig ( field . configKey , checked === true )
245+ }
246+ />
247+ < Label className = "cursor-pointer font-normal" htmlFor = { field . id } >
248+ { field . label }
249+ </ Label >
250+ { renderHelpText ( field . helpText , field . helpLink ) }
251+ </ div >
252+ ) ;
253+ } ;
254+
255+ const renderInputField = ( field : {
256+ id : string ;
257+ type : string ;
258+ label : string ;
259+ configKey : string ;
260+ placeholder ?: string ;
261+ helpText ?: string ;
262+ helpLink ?: { text : string ; url : string } ;
263+ } ) => (
264+ < div className = "space-y-2" key = { field . id } >
265+ < Label htmlFor = { field . id } > { field . label } </ Label >
266+ < Input
267+ id = { field . id }
268+ onChange = { ( e ) => updateConfig ( field . configKey , e . target . value ) }
269+ placeholder = { field . placeholder }
270+ type = { field . type }
271+ value = { ( formData . config [ field . configKey ] as string ) || "" }
272+ />
273+ { renderHelpText ( field . helpText , field . helpLink ) }
274+ </ div >
275+ ) ;
276+
136277 const renderConfigFields = ( ) => {
137278 // Handle system integrations with hardcoded fields
138279 if ( formData . type === "database" ) {
@@ -144,7 +285,7 @@ export function IntegrationFormDialog({
144285 onChange = { ( e ) => updateConfig ( "url" , e . target . value ) }
145286 placeholder = "postgresql://..."
146287 type = "password"
147- value = { formData . config . url || "" }
288+ value = { ( formData . config . url as string ) || "" }
148289 />
149290 < p className = "text-muted-foreground text-xs" >
150291 Connection string in the format:
@@ -165,33 +306,24 @@ export function IntegrationFormDialog({
165306 return null ;
166307 }
167308
168- return plugin . formFields . map ( ( field ) => (
169- < div className = "space-y-2" key = { field . id } >
170- < Label htmlFor = { field . id } > { field . label } </ Label >
171- < Input
172- id = { field . id }
173- onChange = { ( e ) => updateConfig ( field . configKey , e . target . value ) }
174- placeholder = { field . placeholder }
175- type = { field . type }
176- value = { formData . config [ field . configKey ] || "" }
309+ // Handle SendGrid integration with special checkbox logic
310+ if ( formData . type === "sendgrid" ) {
311+ return (
312+ < SendGridIntegrationSection
313+ config = { formData . config }
314+ formFields = { plugin . formFields }
315+ updateConfig = { updateConfig }
177316 />
178- { ( field . helpText || field . helpLink ) && (
179- < p className = "text-muted-foreground text-xs" >
180- { field . helpText }
181- { field . helpLink && (
182- < a
183- className = "underline hover:text-foreground"
184- href = { field . helpLink . url }
185- rel = "noopener noreferrer"
186- target = "_blank"
187- >
188- { field . helpLink . text }
189- </ a >
190- ) }
191- </ p >
192- ) }
193- </ div >
194- ) ) ;
317+ ) ;
318+ }
319+
320+ // Default rendering for other integrations
321+ return plugin . formFields . map ( ( field ) => {
322+ if ( field . type === "checkbox" ) {
323+ return renderCheckboxField ( field ) ;
324+ }
325+ return renderInputField ( field ) ;
326+ } ) ;
195327 } ;
196328
197329 return (
0 commit comments