@@ -6,15 +6,28 @@ import type { ConnectionResponseSchema } from "@repo/validation/api"
66import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query"
77import { GoogleDrive , Notion , OneDrive } from "@ui/assets/icons"
88import { useCustomer } from "autumn-js/react"
9- import { Check , Loader , Trash2 , Zap } from "lucide-react"
9+ import { Check , ChevronDown , Loader , Trash2 , Zap } from "lucide-react"
1010import { useEffect , useState } from "react"
1111import { toast } from "sonner"
1212import type { z } from "zod"
1313import { dmSansClassName } from "@/lib/fonts"
1414import { cn } from "@lib/utils"
1515import { Button } from "@ui/components/button"
16+ import {
17+ DropdownMenu ,
18+ DropdownMenuContent ,
19+ DropdownMenuItem ,
20+ DropdownMenuTrigger ,
21+ } from "@ui/components/dropdown-menu"
1622import { RemoveConnectionDialog } from "@/components/remove-connection-dialog"
1723
24+ type GDriveSyncScope = "scoped" | "full"
25+
26+ const GDRIVE_SCOPE_LABELS : Record < GDriveSyncScope , string > = {
27+ scoped : "Files & Folders" ,
28+ full : "Whole Drive" ,
29+ }
30+
1831type Connection = z . infer < typeof ConnectionResponseSchema >
1932
2033type ConnectorProvider = "google-drive" | "notion" | "onedrive"
@@ -54,6 +67,8 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
5467 const isProUser = hasActivePlan ( autumn . customer ?. products , "api_pro" )
5568 const [ connectingProvider , setConnectingProvider ] =
5669 useState < ConnectorProvider | null > ( null )
70+ const [ gdriveSyncScope , setGdriveSyncScope ] =
71+ useState < GDriveSyncScope > ( "scoped" )
5772 const [ isUpgrading , setIsUpgrading ] = useState ( false )
5873 const [ removeDialog , setRemoveDialog ] = useState < {
5974 open : boolean
@@ -114,7 +129,13 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
114129
115130 // Connect mutation
116131 const addConnectionMutation = useMutation ( {
117- mutationFn : async ( provider : ConnectorProvider ) => {
132+ mutationFn : async ( {
133+ provider,
134+ syncScope,
135+ } : {
136+ provider : ConnectorProvider
137+ syncScope ?: GDriveSyncScope
138+ } ) => {
118139 if ( ! canAddConnection && ! isProUser ) {
119140 throw new Error (
120141 "Free plan doesn't include connections. Upgrade to Pro for unlimited connections." ,
@@ -126,6 +147,10 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
126147 body : {
127148 redirectUrl : window . location . href ,
128149 containerTags : [ selectedProject ] ,
150+ metadata :
151+ provider === "google-drive" && syncScope === "full"
152+ ? { syncScope : "full" }
153+ : undefined ,
129154 } ,
130155 } )
131156
@@ -180,7 +205,10 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
180205
181206 const handleConnect = ( provider : ConnectorProvider ) => {
182207 setConnectingProvider ( provider )
183- addConnectionMutation . mutate ( provider )
208+ addConnectionMutation . mutate ( {
209+ provider,
210+ syncScope : provider === "google-drive" ? gdriveSyncScope : undefined ,
211+ } )
184212 }
185213
186214 const handleDisconnect = ( connection : Connection ) => {
@@ -215,7 +243,66 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
215243 const isConnecting =
216244 connectingProvider === provider ||
217245 ( addConnectionMutation . isPending &&
218- addConnectionMutation . variables === provider )
246+ addConnectionMutation . variables ?. provider === provider )
247+
248+ if ( provider === "google-drive" ) {
249+ return (
250+ < div
251+ key = { provider }
252+ className = "bg-[#14161A] border border-[rgba(82,89,102,0.2)] rounded-[12px] flex overflow-hidden"
253+ >
254+ < button
255+ type = "button"
256+ onClick = { ( ) => handleConnect ( "google-drive" ) }
257+ disabled = {
258+ ! isProUser ||
259+ isConnecting ||
260+ addConnectionMutation . isPending
261+ }
262+ className = "flex-1 py-3 flex items-center justify-center gap-2 hover:bg-[#1B1F24] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
263+ >
264+ < Icon className = "w-6 h-6 text-[#737373]" />
265+ < p className = "text-[14px] font-medium" > { config . title } </ p >
266+ { isConnecting && (
267+ < Loader className = "h-4 w-4 animate-spin text-[#4BA0FA]" />
268+ ) }
269+ </ button >
270+ < div className = "w-px bg-[rgba(82,89,102,0.4)] self-stretch my-2" />
271+ < DropdownMenu >
272+ < DropdownMenuTrigger asChild >
273+ < button
274+ type = "button"
275+ className = "w-8 flex items-center justify-center hover:bg-[#1B1F24] transition-colors"
276+ >
277+ < ChevronDown className = "w-3 h-3 text-[#737373]" />
278+ </ button >
279+ </ DropdownMenuTrigger >
280+ < DropdownMenuContent align = "end" className = "w-40" >
281+ { (
282+ Object . entries ( GDRIVE_SCOPE_LABELS ) as [
283+ GDriveSyncScope ,
284+ string ,
285+ ] [ ]
286+ ) . map ( ( [ scope , label ] ) => (
287+ < DropdownMenuItem
288+ key = { scope }
289+ onClick = { ( e ) => {
290+ e . stopPropagation ( )
291+ setGdriveSyncScope ( scope )
292+ } }
293+ className = "flex items-center justify-between"
294+ >
295+ { label }
296+ { gdriveSyncScope === scope && (
297+ < Check className = "w-3 h-3 text-[#4BA0FA]" />
298+ ) }
299+ </ DropdownMenuItem >
300+ ) ) }
301+ </ DropdownMenuContent >
302+ </ DropdownMenu >
303+ </ div >
304+ )
305+ }
219306
220307 return (
221308 < button
@@ -249,7 +336,7 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
249336 const isConnecting =
250337 connectingProvider === provider ||
251338 ( addConnectionMutation . isPending &&
252- addConnectionMutation . variables === provider )
339+ addConnectionMutation . variables ?. provider === provider )
253340
254341 return (
255342 < div
@@ -285,6 +372,58 @@ export function ConnectContent({ selectedProject }: ConnectContentProps) {
285372 >
286373 < Trash2 className = "h-4 w-4" />
287374 </ Button >
375+ ) : provider === "google-drive" ? (
376+ < div className = "flex items-center rounded-md overflow-hidden" >
377+ < button
378+ type = "button"
379+ onClick = { ( ) => handleConnect ( "google-drive" ) }
380+ disabled = {
381+ ! isProUser ||
382+ isConnecting ||
383+ addConnectionMutation . isPending
384+ }
385+ className = "bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 text-[14px] font-medium px-3 h-8 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
386+ >
387+ { isConnecting ? (
388+ < Loader className = "h-4 w-4 animate-spin" />
389+ ) : (
390+ "Connect"
391+ ) }
392+ </ button >
393+ < div className = "w-px h-5 bg-black/20" />
394+ < DropdownMenu >
395+ < DropdownMenuTrigger asChild >
396+ < button
397+ type = "button"
398+ className = "bg-[#4BA0FA] text-black hover:bg-[#4BA0FA]/90 px-1.5 h-8 flex items-center transition-colors"
399+ >
400+ < ChevronDown className = "w-3 h-3" />
401+ </ button >
402+ </ DropdownMenuTrigger >
403+ < DropdownMenuContent align = "end" className = "w-40" >
404+ { (
405+ Object . entries ( GDRIVE_SCOPE_LABELS ) as [
406+ GDriveSyncScope ,
407+ string ,
408+ ] [ ]
409+ ) . map ( ( [ scope , label ] ) => (
410+ < DropdownMenuItem
411+ key = { scope }
412+ onClick = { ( e ) => {
413+ e . stopPropagation ( )
414+ setGdriveSyncScope ( scope )
415+ } }
416+ className = "flex items-center justify-between"
417+ >
418+ { label }
419+ { gdriveSyncScope === scope && (
420+ < Check className = "w-3 h-3 text-[#4BA0FA]" />
421+ ) }
422+ </ DropdownMenuItem >
423+ ) ) }
424+ </ DropdownMenuContent >
425+ </ DropdownMenu >
426+ </ div >
288427 ) : (
289428 < Button
290429 onClick = { ( ) =>
0 commit comments