IntegrationCard.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import { Check } from 'lucide-react'
  2. import Image from 'next/image'
  3. import { Badge, Button } from 'ui'
  4. import { AWS_IDP_REGIONS } from './AwsRegionSelector'
  5. import {
  6. getIntegrationType,
  7. getIntegrationTypeIcon,
  8. getIntegrationTypeLabel,
  9. INTEGRATION_TYPES,
  10. } from './ThirdPartyAuthForm.utils'
  11. import { ThirdPartyAuthIntegration } from '@/data/third-party-auth/integrations-query'
  12. import { DOCS_URL } from '@/lib/constants'
  13. interface IntegrationCardProps {
  14. integration: ThirdPartyAuthIntegration
  15. canUpdateConfig: boolean
  16. onDelete: () => void
  17. }
  18. export const getIntegrationTypeDescription = (type: INTEGRATION_TYPES) => {
  19. switch (type) {
  20. case 'firebase':
  21. return (
  22. <>
  23. Allow users to use Briven with Firebase project. You'll need to setup RLS policies for
  24. all tables that you want to access with a Firebase JWT token. Additionally, you'll need to
  25. add custom code to set the <code>authenticated</code> role to all your present and future
  26. users. You can read more in the{' '}
  27. <a
  28. className="hover:decoration-brand underline hover:text-foreground transition"
  29. href={`${DOCS_URL}/guides/auth`}
  30. >
  31. documentation
  32. </a>
  33. .
  34. </>
  35. )
  36. case 'auth0':
  37. return (
  38. <>
  39. Allow users to use Briven with Auth0 project. Additional setup may be required. You can
  40. read more in the{' '}
  41. <a
  42. className="hover:decoration-brand underline hover:text-foreground transition"
  43. href={`${DOCS_URL}/guides/auth`}
  44. >
  45. documentation
  46. </a>
  47. .
  48. </>
  49. )
  50. case 'awsCognito':
  51. return (
  52. <>
  53. Allow users to use Briven with an Amazon Cognito. Additional setup may be required. You
  54. can read more in the{' '}
  55. <a
  56. className="hover:decoration-brand underline hover:text-foreground transition"
  57. href={`${DOCS_URL}/guides/auth/third-party/aws-cognito`}
  58. >
  59. documentation
  60. </a>
  61. .
  62. </>
  63. )
  64. case 'clerk':
  65. return (
  66. <>
  67. Allow users to use Briven with Clerk. Additional setup may be required. You can read
  68. more in the{' '}
  69. <a
  70. className="hover:decoration-brand underline hover:text-foreground transition"
  71. href={`${DOCS_URL}/guides/auth/third-party/clerk`}
  72. >
  73. documentation
  74. </a>
  75. .
  76. </>
  77. )
  78. case 'workos':
  79. return (
  80. <>
  81. Allow users to use Briven with WorkOS. Additional setup may be required. You can read
  82. more in the{' '}
  83. <a
  84. className="hover:decoration-brand underline hover:text-foreground transition"
  85. href={`${DOCS_URL}/guides/auth/third-party/workos`}
  86. >
  87. documentation
  88. </a>
  89. .
  90. </>
  91. )
  92. case 'custom':
  93. default:
  94. return 'Custom'
  95. }
  96. }
  97. export const IntegrationTypeContent = ({
  98. type,
  99. integration,
  100. }: {
  101. type: INTEGRATION_TYPES
  102. integration: ThirdPartyAuthIntegration
  103. }) => {
  104. switch (type) {
  105. case 'firebase': {
  106. const projectName =
  107. integration.oidc_issuer_url?.replace('https://securetoken.google.com/', '') || ''
  108. return (
  109. <div className="text-sm flex flex-row gap-x-4">
  110. <span className="text-foreground-light w-36">Firebase Project ID</span>
  111. <span className="text-foreground">{projectName}</span>
  112. </div>
  113. )
  114. }
  115. case 'auth0':
  116. const domainName =
  117. integration.oidc_issuer_url?.replace('https://', '').replace('.auth0.com', '') || ''
  118. return (
  119. <div className="text-sm flex flex-row gap-x-4">
  120. <span className="text-foreground-light w-36">Auth0 Domain Name</span>
  121. <span className="text-foreground">{domainName}</span>
  122. </div>
  123. )
  124. case 'awsCognito': {
  125. const region =
  126. integration.oidc_issuer_url?.split('.').filter((s) => AWS_IDP_REGIONS.includes(s))[0] || ''
  127. const userPoolId =
  128. integration.oidc_issuer_url?.split('/').filter((s) => s.startsWith(region || ''))[0] || ''
  129. return (
  130. <div className="text-sm flex flex-col gap-y-2">
  131. <div className="flex flex-row gap-x-4">
  132. <span className="text-foreground-light w-36">Region</span>
  133. <span className="text-foreground">{region}</span>
  134. </div>
  135. <div className="flex flex-row gap-x-4">
  136. <span className="text-foreground-light w-36">User Pool ID</span>
  137. <span className="text-foreground">{userPoolId}</span>
  138. </div>
  139. </div>
  140. )
  141. }
  142. case 'clerk':
  143. return (
  144. <div className="text-sm flex flex-row gap-x-4">
  145. <span className="text-foreground-light w-36">Domain</span>
  146. <span className="text-foreground">{integration?.oidc_issuer_url ?? ''}</span>
  147. </div>
  148. )
  149. case 'workos':
  150. return (
  151. <div className="text-sm flex flex-row gap-x-4">
  152. <span className="text-foreground-light w-36">Issuer URL</span>
  153. <span className="text-foreground">{integration?.oidc_issuer_url ?? ''}</span>
  154. </div>
  155. )
  156. case 'custom':
  157. default:
  158. return <>Custom</>
  159. }
  160. }
  161. export const IntegrationCard = ({
  162. integration,
  163. canUpdateConfig,
  164. onDelete,
  165. }: IntegrationCardProps) => {
  166. let type = getIntegrationType(integration)
  167. if (type === 'custom') {
  168. return null
  169. }
  170. return (
  171. <>
  172. <div className="bg-surface-100 border overflow-hidden shadow-sm px-5 py-4 flex flex-row first:rounded-t-md last:rounded-b-md space-x-4">
  173. <div className="py-1">
  174. <Image src={getIntegrationTypeIcon(type)} width={21} height={21} alt={`${type} icon`} />
  175. </div>
  176. <div className="flex min-w-0 flex-1 flex-col gap-y-4 overflow-y-auto">
  177. <div className="text-sm flex flex-col">
  178. <span className="text-foreground">{getIntegrationTypeLabel(type)}</span>
  179. <div className="text-foreground-lighter">{getIntegrationTypeDescription(type)}</div>
  180. </div>
  181. <IntegrationTypeContent type={type} integration={integration} />
  182. <div>
  183. {/* TODO: this should be a configure integration where it would show the sheet and the user can disable or delete the integration
  184. but there's no "edit integration" endpoing for now. */}
  185. <Button type="danger" disabled={!canUpdateConfig} onClick={() => onDelete()}>
  186. Delete integration
  187. </Button>
  188. </div>
  189. </div>
  190. <div className="shrink-0">
  191. {true ? (
  192. <Badge className="space-x-1" variant="success">
  193. <div className="h-3.5 w-3.5 bg-brand rounded-full flex justify-center items-center">
  194. <Check className="h-2 w-2 text-background-overlay" strokeWidth={6} />
  195. </div>
  196. <span>Enabled</span>
  197. </Badge>
  198. ) : (
  199. <Badge variant="warning">
  200. <span>Disabled</span>
  201. </Badge>
  202. )}
  203. </div>
  204. </div>
  205. </>
  206. )
  207. }