SendEmailDialog.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. 'use client'
  2. import { handleGated } from '@/components/upgrade-gate'
  3. import type { GatedFeature } from '@/lib/with-auth'
  4. import { useState } from 'react'
  5. import { Button } from '@/components/ui/button'
  6. import { Input } from '@/components/ui/input'
  7. import { Label } from '@/components/ui/label'
  8. import { Textarea } from '@/components/ui/textarea'
  9. import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
  10. import { Loader2, Mail, Send } from 'lucide-react'
  11. import { useGlassModal } from '@/components/glass-modal'
  12. import { AttachPdfOption, useAttachPdf } from '@/features/email/Components/AttachPdfOption'
  13. interface SendEmailDialogProps {
  14. open: boolean
  15. onOpenChange: (open: boolean) => void
  16. defaultEmail?: string
  17. entityLabel: string
  18. onSend: (
  19. email: string,
  20. message?: string,
  21. attachPdf?: boolean
  22. ) => Promise<{ success: boolean; error?: string; gated?: GatedFeature }>
  23. }
  24. export function SendEmailDialog({
  25. open,
  26. onOpenChange,
  27. defaultEmail = '',
  28. entityLabel,
  29. onSend,
  30. }: SendEmailDialogProps) {
  31. const modal = useGlassModal()
  32. const [sending, setSending] = useState(false)
  33. const [email, setEmail] = useState(defaultEmail)
  34. const [message, setMessage] = useState('')
  35. const [attachPdf, setAttachPdf] = useAttachPdf(open)
  36. const handleSend = async (e: React.FormEvent) => {
  37. e.preventDefault()
  38. if (!email) return
  39. setSending(true)
  40. const result = await onSend(email, message || undefined, attachPdf)
  41. if (result.success) {
  42. modal.open('success', 'Email Sent', `${entityLabel} has been sent to ${email}`)
  43. onOpenChange(false)
  44. setMessage('')
  45. } else if (handleGated(result)) {
  46. onOpenChange(false)
  47. } else {
  48. modal.open('error', 'Error', result.error || 'Failed to send email')
  49. }
  50. setSending(false)
  51. }
  52. return (
  53. <Dialog open={open} onOpenChange={onOpenChange}>
  54. <DialogContent className="max-w-md" aria-describedby={undefined}>
  55. <DialogHeader>
  56. <DialogTitle className="flex items-center gap-2">
  57. <Mail className="h-5 w-5" />
  58. Send {entityLabel}
  59. </DialogTitle>
  60. </DialogHeader>
  61. <form onSubmit={handleSend} className="space-y-4">
  62. <div className="space-y-2">
  63. <Label htmlFor="email">Recipient Email</Label>
  64. <Input
  65. id="email"
  66. type="email"
  67. placeholder="customer@example.com"
  68. value={email}
  69. onChange={(e) => setEmail(e.target.value)}
  70. required
  71. />
  72. </div>
  73. <div className="space-y-2">
  74. <Label htmlFor="message">Message (optional)</Label>
  75. <Textarea
  76. id="message"
  77. placeholder="Add a personal message..."
  78. value={message}
  79. onChange={(e) => setMessage(e.target.value)}
  80. rows={3}
  81. />
  82. </div>
  83. <AttachPdfOption
  84. id="attach-pdf-send"
  85. checked={attachPdf}
  86. onCheckedChange={setAttachPdf}
  87. />
  88. <div className="flex justify-end gap-2">
  89. <Button type="button" variant="ghost" onClick={() => onOpenChange(false)}>
  90. Cancel
  91. </Button>
  92. <Button type="submit" disabled={sending || !email}>
  93. {sending ? (
  94. <Loader2 className="mr-2 h-4 w-4 animate-spin" />
  95. ) : (
  96. <Send className="mr-2 h-4 w-4" />
  97. )}
  98. Send Email
  99. </Button>
  100. </div>
  101. </form>
  102. </DialogContent>
  103. </Dialog>
  104. )
  105. }