vendor: 7,742 bytes, lines 1-234
1import { c as createLucideIcon, r as reactExports, A as useComposedRefs, H as useControllableState, j as jsxRuntimeExports, w as createContextScope, y as Primitive, z as composeEventHandlers, aF as useSize, V as cn, a as useAgentAuth, t as trpc, b as toast, B as Button, P as Pencil, h as Star, o as RefreshCw, M as Mail, X, T as TriangleAlert, S as Shield, E as Eye, L as LoaderCircle } from './index-CNT5CkK7.js'; 2import { I as Input } from './input-Dy4-W9m0.js'; 3import { L as Label } from './label-BdZn6Q6n.js'; 4import { C as Card, b as CardHeader, c as CardTitle, a as CardContent, d as CardDescription } from './card-CV3CzesJ.js'; 5import { u as usePrevious } from './index-B88B3rZe.js'; 6import { U as User } from './user-B4RG8T6t.js'; 7import { L as Link2 } from './link-2-fjaVShKv.js'; 8import { S as Save } from './save-PDl6zfI9.js'; 9import { C as CircleCheck } from './circle-check-CqW-unub.js'; 10import { C as CircleX } from './circle-x-Bp9RgmBn.js'; 11import { C as Calendar } from './calendar-CGh5WTcU.js'; 12import './useComposition-DPCJbBnn.js'; 13 14/** 15 * @license lucide-react v0.453.0 - ISC 16 * 17 * This source code is licensed under the ISC license. 18 * See the LICENSE file in the root directory of this source tree. 19 */ 20 21 22const TestTubeDiagonal = createLucideIcon("TestTubeDiagonal", [ 23 [ 24 "path", 25 { d: "M21 7 6.82 21.18a2.83 2.83 0 0 1-3.99-.01a2.83 2.83 0 0 1 0-4L17 3", key: "1ub6xw" } 26 ], 27 ["path", { d: "m16 2 6 6", key: "1gw87d" }], 28 ["path", { d: "M12 16H4", key: "1cjfip" }] 29]); 30 31/** 32 * @license lucide-react v0.453.0 - ISC 33 * 34 * This source code is licensed under the ISC license. 35 * See the LICENSE file in the root directory of this source tree. 36 */ 37 38 39const Unplug = createLucideIcon("Unplug", [ 40 ["path", { d: "m19 5 3-3", key: "yk6iyv" }], 41 ["path", { d: "m2 22 3-3", key: "19mgm9" }], 42 [ 43 "path", 44 { d: "M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z", key: "goz73y" } 45 ], 46 ["path", { d: "M7.5 13.5 10 11", key: "7xgeeb" }], 47 ["path", { d: "M10.5 16.5 13 14", key: "10btkg" }], 48 [ 49 "path", 50 { d: "m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z", key: "1snsnr" } 51 ] 52]); 53 54var SWITCH_NAME = "Switch"; 55var [createSwitchContext] = createContextScope(SWITCH_NAME); 56var [SwitchProvider, useSwitchContext] = createSwitchContext(SWITCH_NAME); 57var Switch$1 = reactExports.forwardRef( 58 (props, forwardedRef) => { 59 const { 60 __scopeSwitch, 61 name, 62 checked: checkedProp, 63 defaultChecked, 64 required, 65 disabled, 66 value = "on", 67 onCheckedChange, 68 form, 69 ...switchProps 70 } = props; 71 const [button, setButton] = reactExports.useState(null); 72 const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node)); 73 const hasConsumerStoppedPropagationRef = reactExports.useRef(false); 74 const isFormControl = button ? form || !!button.closest("form") : true; 75 const [checked, setChecked] = useControllableState({ 76 prop: checkedProp, 77 defaultProp: defaultChecked ?? false, 78 onChange: onCheckedChange, 79 caller: SWITCH_NAME 80 }); 81 return /* @__PURE__ */ jsxRuntimeExports.jsxs(SwitchProvider, { scope: __scopeSwitch, checked, disabled, children: [ 82 /* @__PURE__ */ jsxRuntimeExports.jsx( 83 Primitive.button, 84 { 85 type: "button", 86 role: "switch", 87 "aria-checked": checked, 88 "aria-required": required, 89 "data-state": getState(checked), 90 "data-disabled": disabled ? "" : void 0, 91 disabled, 92 value, 93 ...switchProps, 94 ref: composedRefs, 95 onClick: composeEventHandlers(props.onClick, (event) => { 96 setChecked((prevChecked) => !prevChecked); 97 if (isFormControl) { 98 hasConsumerStoppedPropagationRef.current = event.isPropagationStopped(); 99 if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation(); 100 } 101 }) 102 } 103 ), 104 isFormControl && /* @__PURE__ */ jsxRuntimeExports.jsx( 105 SwitchBubbleInput, 106 { 107 control: button, 108 bubbles: !hasConsumerStoppedPropagationRef.current, 109 name, 110 value, 111 checked, 112 required, 113 disabled, 114 form, 115 style: { transform: "translateX(-100%)" } 116 } 117 ) 118 ] }); 119 } 120); 121Switch$1.displayName = SWITCH_NAME; 122var THUMB_NAME = "SwitchThumb"; 123var SwitchThumb = reactExports.forwardRef( 124 (props, forwardedRef) => { 125 const { __scopeSwitch, ...thumbProps } = props; 126 const context = useSwitchContext(THUMB_NAME, __scopeSwitch); 127 return /* @__PURE__ */ jsxRuntimeExports.jsx( 128 Primitive.span, 129 { 130 "data-state": getState(context.checked), 131 "data-disabled": context.disabled ? "" : void 0, 132 ...thumbProps, 133 ref: forwardedRef 134 } 135 ); 136 } 137); 138SwitchThumb.displayName = THUMB_NAME; 139var BUBBLE_INPUT_NAME = "SwitchBubbleInput"; 140var SwitchBubbleInput = reactExports.forwardRef( 141 ({ 142 __scopeSwitch, 143 control, 144 checked, 145 bubbles = true, 146 ...props 147 }, forwardedRef) => { 148 const ref = reactExports.useRef(null); 149 const composedRefs = useComposedRefs(ref, forwardedRef); 150 const prevChecked = usePrevious(checked); 151 const controlSize = useSize(control); 152 reactExports.useEffect(() => { 153 const input = ref.current; 154 if (!input) return; 155 const inputProto = window.HTMLInputElement.prototype; 156 const descriptor = Object.getOwnPropertyDescriptor( 157 inputProto, 158 "checked" 159 ); 160 const setChecked = descriptor.set; 161 if (prevChecked !== checked && setChecked) { 162 const event = new Event("click", { bubbles }); 163 setChecked.call(input, checked); 164 input.dispatchEvent(event); 165 } 166 }, [prevChecked, checked, bubbles]); 167 return /* @__PURE__ */ jsxRuntimeExports.jsx( 168 "input", 169 { 170 type: "checkbox", 171 "aria-hidden": true, 172 defaultChecked: checked, 173 ...props, 174 tabIndex: -1, 175 ref: composedRefs, 176 style: { 177 ...props.style, 178 ...controlSize, 179 position: "absolute", 180 pointerEvents: "none", 181 opacity: 0, 182 margin: 0 183 } 184 } 185 ); 186 } 187); 188SwitchBubbleInput.displayName = BUBBLE_INPUT_NAME; 189function getState(checked) { 190 return checked ? "checked" : "unchecked"; 191} 192var Root = Switch$1; 193var Thumb = SwitchThumb; 194 195function Switch({ 196 className, 197 ...props 198}) { 199 return /* @__PURE__ */ jsxRuntimeExports.jsx( 200 Root, 201 { 202 "data-slot": "switch", 203 className: cn( 204 "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50", 205 className 206 ), 207 ...props, 208 children: /* @__PURE__ */ jsxRuntimeExports.jsx( 209 Thumb, 210 { 211 "data-slot": "switch-thumb", 212 className: cn( 213 "bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0" 214 ) 215 } 216 ) 217 } 218 ); 219} 220 221const CALENDAR_AGENTS = [ 222 "greg-fay", 223 "stacey-hinkle", 224 "ryan-fay", 225 "josh-hinkle", 226 "zach-hinkle", 227 "angie-hinkle", 228 "jon-bucher", 229 "emily-bucher", 230 "charlie-drain", 231 "michael-jividen", 232 "adam-kaufman", 233 "lesley-wiegand" 234];
235function GoogleCalendarCard({ agentKey }) { 236 const utils = trpc.useUtils(); 237 const { data: calStatus, isLoading: calLoading } = trpc.googleCalendar.getConnectionStatus.useQuery( 238 { agentKey }, 239 { enabled: !!agentKey && CALENDAR_AGENTS.includes(agentKey), refetchOnWindowFocus: true } 240 ); 241 const disconnect = trpc.googleCalendar.disconnect.useMutation({ 242 onSuccess: () => { 243 toast.success("Google Calendar disconnected"); 244 utils.googleCalendar.getConnectionStatus.invalidate(); 245 }, 246 onError: (e) => toast.error(e.message) 247 }); 248 const [isWarmingUp, setIsWarmingUp] = reactExports.useState(false); 249 const handleConnect = async () => { 250 setIsWarmingUp(true); 251 try { 252 await fetch("/api/ping").catch(() => { 253 }); 254 await new Promise((r) => setTimeout(r, 800)); 255 } finally { 256 setIsWarmingUp(false); 257 } 258 window.location.href = `/api/google/oauth/start?agentKey=${agentKey}&returnPath=/email-settings`; 259 }; 260 if (!agentKey || !CALENDAR_AGENTS.includes(agentKey)) return null; 261 return /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-[#2d2c5a] border-[#3C3B6E]", children: [ 262 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "pb-3", children: [
263 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base text-white flex items-center gap-2", children: [ 264 /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { className: "w-4 h-4", style: { color: "#B22234" } }), 265 "Google Calendar Sync" 266 ] }), 267 /* @__PURE__ */ jsxRuntimeExports.jsx(CardDescription, { className: "text-white/50 text-xs mt-0.5", children: "Connect your Google Calendar for two-way live sync with the EPS dashboard." }) 268 ] }), 269 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "space-y-3", children: calLoading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-white/40 text-sm", children: [ 270 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-4 h-4 animate-spin" }), 271 " Checking connectionâ¦" 272 ] }) : calStatus?.connected ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 273 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
274 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 275 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-green-400" }), 276 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 277 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white text-sm font-medium", children: "Connected" }), 278 calStatus.googleEmail && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white/50 text-xs", children: calStatus.googleEmail }) 279 ] }) 280 ] }), 281 /* @__PURE__ */ jsxRuntimeExports.jsx( 282 Button, 283 { 284 variant: "outline", 285 size: "sm", 286 className: "text-xs border-red-500/40 text-red-400 hover:bg-red-500/10 hover:text-red-300", 287 onClick: () => { 288 if (confirm("Disconnect Google Calendar? Your existing synced events will remain but won't update.")) disconnect.mutate({ agentKey }); 289 }, 290 disabled: disconnect.isPending,
291 children: disconnect.isPending ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 292 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-3.5 h-3.5 mr-1.5 animate-spin" }), 293 "Disconnectingâ¦" 294 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 295 /* @__PURE__ */ jsxRuntimeExports.jsx(Unplug, { className: "w-3.5 h-3.5 mr-1.5" }), 296 "Disconnect" 297 ] }) 298 } 299 ) 300 ] }), 301 calStatus.tokenExpired && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-red-500/40 bg-red-500/10 px-4 py-3 flex items-start gap-3", children: [ 302 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-red-400 shrink-0 mt-0.5" }), 303 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 304 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-red-300 text-xs font-semibold", children: "Calendar sync has stopped â reconnect required" }),
305 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-red-300/70 text-xs", children: "Your Google authorization has expired. Click Reconnect to restore sync." }), 306 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", className: "text-xs font-semibold", style: { background: "#B22234", color: "white" }, onClick: handleConnect, disabled: isWarmingUp, children: isWarmingUp ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 307 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-3.5 h-3.5 mr-1.5 animate-spin" }), 308 "Preparingâ¦" 309 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 310 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3.5 h-3.5 mr-1.5" }), 311 "Reconnect Google Calendar" 312 ] }) }) 313 ] }) 314 ] }), 315 !calStatus.tokenExpired && calStatus.tokenExpiringSoon && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-yellow-500/40 bg-yellow-500/10 px-4 py-3 flex items-start gap-3", children: [
316 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-yellow-400 shrink-0 mt-0.5" }), 317 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 318 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-yellow-300 text-xs font-semibold", children: "Authorization expires soon" }), 319 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-yellow-300/70 text-xs", children: "Your connection will stop syncing in less than 3 days. Reconnect now to avoid interruption." }), 320 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", className: "text-xs font-semibold", style: { background: "#B22234", color: "white" }, onClick: handleConnect, disabled: isWarmingUp, children: isWarmingUp ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 321 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-3.5 h-3.5 mr-1.5 animate-spin" }), 322 "Preparingâ¦" 323 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
324 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3.5 h-3.5 mr-1.5" }), 325 "Reconnect Now" 326 ] }) }) 327 ] }) 328 ] }), 329 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg px-4 py-3 text-xs text-white/50 space-y-1", style: { background: "rgba(255,255,255,0.04)" }, children: [ 330 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "â Events sync automatically every 30 minutes." }), 331 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "â Events created in the dashboard are pushed to Google Calendar immediately." }) 332 ] }) 333 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 334 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-4", children: [ 335 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 336 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
337 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "w-4 h-4 text-white/30" }), 338 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/50 text-sm", children: "Not connected" }) 339 ] }), 340 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white/40 text-xs", children: "Connect your Google account to start syncing your calendar with the EPS dashboard." }) 341 ] }), 342 /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", className: "text-xs font-semibold flex-shrink-0", style: { background: "#B22234", color: "white" }, onClick: handleConnect, disabled: isWarmingUp, children: isWarmingUp ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 343 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-3.5 h-3.5 mr-1.5 animate-spin" }), 344 "Preparingâ¦" 345 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 346 /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { className: "w-3.5 h-3.5 mr-1.5" }), 347 "Connect Google Calendar" 348 ] }) }) 349 ] }),
350 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg px-4 py-3 text-xs text-white/40 space-y-1", style: { background: "rgba(255,255,255,0.04)" }, children: [ 351 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "â You will be redirected to Google to authorize access to your calendar." }), 352 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "â Make sure you are signed into the correct Google account before clicking Connect." }) 353 ] }) 354 ] }) }) 355 ] }); 356} 357function AgentEmailSettings() { 358 const { agent: agentSession } = useAgentAuth(); 359 const agentKey = agentSession?.agentKey ?? ""; 360 const { data: profile, refetch: refetchProfile } = trpc.agentAuth.getProfile.useQuery( 361 { agentKey }, 362 { enabled: !!agentKey } 363 ); 364 const [editingProfile, setEditingProfile] = reactExports.useState(false); 365 const [profileEmail, setProfileEmail] = reactExports.useState(""); 366 const [profileCalendly, setProfileCalendly] = reactExports.useState(""); 367 const [profileGoogleReview, setProfileGoogleReview] = reactExports.useState(""); 368 const [autoGoogleReview, setAutoGoogleReview] = reactExports.useState(true); 369 reactExports.useEffect(() => { 370 if (profile && !editingProfile) { 371 setProfileEmail(profile.email ?? ""); 372 setProfileCalendly(profile.calendlyLink ?? ""); 373 setProfileGoogleReview(profile.googleReviewLink ?? ""); 374 setAutoGoogleReview(profile.autoGoogleReviewOnPolicyChange ?? true); 375 } 376 }, [profile, editingProfile]); 377 const sendTestReviewEmail = trpc.googleReview.sendTestEmail.useMutation({ 378 onSuccess: (data) => toast.success(`Test email sent to ${data.sentTo}! Check your inbox.`), 379 onError: (err) => toast.error(err.message) 380 }); 381 const updateSelf = trpc.agentAuth.updateSelf.useMutation({ 382 onSuccess: () => { 383 toast.success("Profile updated successfully!"); 384 setEditingProfile(false); 385 refetchProfile(); 386 }, 387 onError: (err) => toast.error(err.message) 388 }); 389 const handleSaveProfile = () => { 390 if (profileEmail && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(profileEmail)) { 391 toast.error("Please enter a valid email address."); 392 return; 393 } 394 if (profileCalendly && !/^https?:\/\//.test(profileCalendly)) { 395 toast.error("Calendly link must start with https://"); 396 return; 397 } 398 if (profileGoogleReview && !/^https?:\/\//.test(profileGoogleReview)) { 399 toast.error("Google Review link must start with https://"); 400 return; 401 } 402 updateSelf.mutate({ 403 agentKey, 404 email: profileEmail || null, 405 calendlyLink: profileCalendly || null, 406 googleReviewLink: profileGoogleReview || null, 407 autoGoogleReviewOnPolicyChange: autoGoogleReview 408 }); 409 }; 410 const { data: status, refetch } = trpc.agentAuth.getSmtpStatus.useQuery( 411 { agentKey }, 412 { enabled: !!agentKey } 413 ); 414 const saveMutation = trpc.agentAuth.saveSMTP.useMutation({ 415 onSuccess: () => { 416 toast.success("Email address saved successfully!"); 417 setEmail(""); 418 refetch(); 419 }, 420 onError: (err) => toast.error(err.message) 421 }); 422 const testMutation = trpc.agentAuth.testSMTP.useMutation({ 423 onSuccess: (result) => { 424 setAzureStatus(result.azureStatus ?? null); 425 if (result.success) { 426 if (result.azureStatus === "azure_failed_gmail_fallback") { 427 toast.success(result.message, { duration: 6e3 }); 428 } else { 429 toast.success(result.message, { duration: 6e3 }); 430 } 431 } else { 432 toast.error(`Connection failed: ${result.message}`, { duration: 8e3 }); 433 } 434 }, 435 onError: (err) => toast.error(err.message) 436 }); 437 const disconnectMutation = trpc.agentAuth.disconnectSMTP.useMutation({ 438 onSuccess: () => { 439 toast.success("Email disconnected."); 440 refetch(); 441 }, 442 onError: (err) => toast.error(err.message) 443 }); 444 const [email, setEmail] = reactExports.useState(""); 445 const [azureStatus, setAzureStatus] = reactExports.useState(null); 446 const [previewTab, setPreviewTab] = reactExports.useState("request"); 447 const [previewLinkOverride, setPreviewLinkOverride] = reactExports.useState(void 0); 448 const debounceRef = reactExports.useRef(null); 449 reactExports.useEffect(() => { 450 if (!editingProfile) return; 451 if (debounceRef.current) clearTimeout(debounceRef.current); 452 debounceRef.current = setTimeout(() => { 453 const val = profileGoogleReview.trim(); 454 setPreviewLinkOverride(val.startsWith("http") ? val : void 0); 455 }, 600); 456 return () => { 457 if (debounceRef.current) clearTimeout(debounceRef.current); 458 }; 459 }, [profileGoogleReview, editingProfile]); 460 const { data: previewData, isFetching: previewFetching } = trpc.googleReview.previewEmail.useQuery( 461 {
462 agentKey, 463 googleReviewLinkOverride: previewLinkOverride 464 }, 465 { enabled: !!agentKey, staleTime: 0 } 466 ); 467 if (!agentKey) { 468 return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-8 text-center text-muted-foreground", children: "Loading your session..." }); 469 } 470 const isConnected = status?.isConnected ?? false; 471 const handleSaveSmtp = () => { 472 if (!email) { 473 toast.error("Please enter your Microsoft 365 / Outlook email address."); 474 return; 475 } 476 saveMutation.mutate({ 477 agentKey, 478 smtpEmail: email, 479 smtpPassword: "oauth2-managed", 480 smtpProvider: "outlook" 481 }); 482 }; 483 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-2xl mx-auto p-6 space-y-6", children: [ 484 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 485 /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-2xl font-bold text-white", children: "Account Settings" }), 486 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground mt-1", children: "Update your profile information and email integration settings." }) 487 ] }), 488 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-[#2d2c5a] border-[#3C3B6E]", children: [
489 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 490 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base text-white flex items-center gap-2", children: [ 491 /* @__PURE__ */ jsxRuntimeExports.jsx(User, { className: "w-4 h-4" }), 492 "My Profile" 493 ] }), 494 !editingProfile && /* @__PURE__ */ jsxRuntimeExports.jsxs( 495 Button, 496 { 497 variant: "ghost", 498 size: "sm", 499 onClick: () => setEditingProfile(true), 500 className: "text-white/70 hover:text-white hover:bg-white/10 gap-1.5", 501 children: [ 502 /* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { className: "w-3.5 h-3.5" }), 503 "Edit Profile" 504 ] 505 } 506 ) 507 ] }) }), 508 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { children: !editingProfile ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
509 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 510 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] font-semibold text-white/40 uppercase tracking-widest mb-1", children: "Name" }), 511 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white text-sm font-medium", children: profile?.agentName ?? agentSession?.agentName ?? "â" }) 512 ] }), 513 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 514 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] font-semibold text-white/40 uppercase tracking-widest mb-1", children: "Professional Email" }), 515 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white text-sm", children: profile?.email ?? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 italic", children: "Not set" }) }) 516 ] }), 517 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 518 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] font-semibold text-white/40 uppercase tracking-widest mb-1", children: "Calendly Link" }), 519 profile?.calendlyLink ? /* @__PURE__ */ jsxRuntimeExports.jsxs("a", { href: profile.calendlyLink, target: "_blank", rel: "noopener noreferrer", className: "text-blue-400 hover:text-blue-300 text-sm flex items-center gap-1", children: [
520 /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { className: "w-3 h-3" }), 521 profile.calendlyLink.replace("https://", "") 522 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 italic text-sm", children: "Not set" }) 523 ] }), 524 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 525 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] font-semibold text-white/40 uppercase tracking-widest mb-1", children: "Google Review Link" }), 526 profile?.googleReviewLink ? /* @__PURE__ */ jsxRuntimeExports.jsxs("a", { href: profile.googleReviewLink, target: "_blank", rel: "noopener noreferrer", className: "text-green-400 hover:text-green-300 text-sm flex items-center gap-1", children: [ 527 /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { className: "w-3 h-3" }), 528 profile.googleReviewLink.replace("https://", "") 529 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 italic text-sm", children: "Not set" }) 530 ] }),
531 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2", children: [ 532 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] font-semibold text-white/40 uppercase tracking-widest mb-1", children: "Auto Google Review on Policy Change" }), 533 profile?.autoGoogleReviewOnPolicyChange !== false ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-green-400 text-sm flex items-center gap-1", children: [ 534 /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-3 h-3" }), 535 " Enabled â clients receive review request automatically" 536 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 italic text-sm", children: "Disabled" }) 537 ] }) 538 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 539 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 540 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-white text-sm", children: "Professional Email" }),
541 /* @__PURE__ */ jsxRuntimeExports.jsx( 542 Input, 543 { 544 type: "email", 545 placeholder: "[email protected]", 546 value: profileEmail, 547 onChange: (e) => setProfileEmail(e.target.value), 548 className: "bg-[#3C3B6E] border-[#3C3B6E] text-white placeholder:text-muted-foreground" 549 } 550 ), 551 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "This is the email address displayed on your profile and used for notifications." }) 552 ] }), 553 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 554 /* @__PURE__ */ jsxRuntimeExports.jsxs(Label, { className: "text-white text-sm", children: [ 555 "Calendly Link ", 556 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 font-normal", children: "(optional)" }) 557 ] }), 558 /* @__PURE__ */ jsxRuntimeExports.jsx( 559 Input, 560 { 561 type: "url", 562 placeholder: "https://calendly.com/yourname", 563 value: profileCalendly, 564 onChange: (e) => setProfileCalendly(e.target.value), 565 className: "bg-[#3C3B6E] border-[#3C3B6E] text-white placeholder:text-muted-foreground" 566 } 567 ) 568 ] }),
569 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 570 /* @__PURE__ */ jsxRuntimeExports.jsxs(Label, { className: "text-white text-sm", children: [ 571 "Google Review Link ", 572 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-white/40 font-normal", children: "(optional)" }) 573 ] }), 574 /* @__PURE__ */ jsxRuntimeExports.jsx( 575 Input, 576 { 577 type: "url", 578 placeholder: "https://g.page/r/your-review-link/review", 579 value: profileGoogleReview, 580 onChange: (e) => setProfileGoogleReview(e.target.value), 581 className: "bg-[#3C3B6E] border-[#3C3B6E] text-white placeholder:text-muted-foreground" 582 } 583 ), 584 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Clients will be sent this link after their policy change is marked complete." }), 585 /* @__PURE__ */ jsxRuntimeExports.jsx( 586 Button, 587 { 588 type: "button", 589 variant: "outline", 590 size: "sm", 591 disabled: sendTestReviewEmail.isPending || !profileGoogleReview && !profile?.googleReviewLink, 592 onClick: () => sendTestReviewEmail.mutate({ 593 agentKey, 594 googleReviewLink: profileGoogleReview || void 0 595 }), 596 className: "mt-2 gap-1.5 text-xs border-[#3C3B6E] text-white/70 hover:text-white hover:bg-white/10",
597 children: sendTestReviewEmail.isPending ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 598 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-3 h-3 animate-spin" }), 599 " Sending..." 600 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 601 /* @__PURE__ */ jsxRuntimeExports.jsx(Mail, { className: "w-3 h-3" }), 602 " Send Test Email" 603 ] }) 604 } 605 ) 606 ] }), 607 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between rounded-lg bg-[#3C3B6E]/50 border border-[#3C3B6E] px-4 py-3", children: [ 608 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-0.5", children: [ 609 /* @__PURE__ */ jsxRuntimeExports.jsxs(Label, { className: "text-white text-sm flex items-center gap-1.5 cursor-pointer", children: [ 610 /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-3.5 h-3.5 text-yellow-400" }), 611 "Auto-send Google Review on Policy Change" 612 ] }),
613 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "When enabled, clients automatically receive a Google review request when their policy change is marked complete." }) 614 ] }), 615 /* @__PURE__ */ jsxRuntimeExports.jsx( 616 Switch, 617 { 618 checked: autoGoogleReview, 619 onCheckedChange: setAutoGoogleReview, 620 className: "ml-4 shrink-0" 621 } 622 ) 623 ] }), 624 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-1", children: [ 625 /* @__PURE__ */ jsxRuntimeExports.jsxs( 626 Button, 627 { 628 onClick: handleSaveProfile, 629 disabled: updateSelf.isPending, 630 className: "bg-[#B22234] hover:bg-[#b8973b] text-white font-semibold gap-1.5", 631 children: [ 632 /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { className: "w-3.5 h-3.5" }), 633 updateSelf.isPending ? "Saving..." : "Save Changes" 634 ] 635 } 636 ),
637 /* @__PURE__ */ jsxRuntimeExports.jsxs( 638 Button, 639 { 640 variant: "ghost", 641 onClick: () => { 642 setEditingProfile(false); 643 setProfileEmail(profile?.email ?? ""); 644 setProfileCalendly(profile?.calendlyLink ?? ""); 645 setProfileGoogleReview(profile?.googleReviewLink ?? ""); 646 setAutoGoogleReview(profile?.autoGoogleReviewOnPolicyChange ?? true); 647 }, 648 className: "text-white/60 hover:text-white gap-1.5", 649 children: [ 650 /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-3.5 h-3.5" }), 651 "Cancel" 652 ] 653 } 654 ) 655 ] }) 656 ] }) }) 657 ] }), 658 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 659 /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-lg font-semibold text-white mb-1 flex items-center gap-2", children: [ 660 /* @__PURE__ */ jsxRuntimeExports.jsx(Mail, { className: "w-4 h-4 text-[#B22234]" }), 661 "Microsoft Outlook Integration" 662 ] }),
663 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground text-sm mb-4", children: "Connect your Outlook account so policy change notifications and client emails are sent from your personal address." }) 664 ] }), 665 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-[#2d2c5a] border-[#3C3B6E]", children: [ 666 /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base text-white flex items-center gap-2", children: [ 667 /* @__PURE__ */ jsxRuntimeExports.jsx(Mail, { className: "w-4 h-4" }), 668 "Connection Status" 669 ] }) }), 670 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { children: isConnected ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 671 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 672 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
673 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-5 h-5 text-green-400" }), 674 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 675 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-white font-medium", children: status?.smtpEmail }), 676 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Microsoft 365 ⢠Secured via Azure OAuth2" }), 677 status?.smtpConnectedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground", children: [ 678 "Connected ", 679 new Date(status.smtpConnectedAt).toLocaleDateString() 680 ] }) 681 ] }) 682 ] }), 683 /* @__PURE__ */ jsxRuntimeExports.jsxs( 684 Button, 685 { 686 variant: "outline", 687 size: "sm", 688 onClick: () => disconnectMutation.mutate({ agentKey }), 689 disabled: disconnectMutation.isPending, 690 className: "border-red-800 text-red-400 hover:bg-red-950", 691 children: [
692 /* @__PURE__ */ jsxRuntimeExports.jsx(Unplug, { className: "w-3.5 h-3.5 mr-1.5" }), 693 "Disconnect" 694 ] 695 } 696 ) 697 ] }), 698 azureStatus === "azure_failed_gmail_fallback" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-lg bg-amber-950/40 border border-amber-700/50 p-3 space-y-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2", children: [ 699 /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "w-4 h-4 text-amber-400 mt-0.5 shrink-0" }), 700 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 701 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-semibold text-amber-300", children: "Azure OAuth2 Authentication Failed" }), 702 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-amber-200/80", children: "The dashboard could not authenticate with Microsoft Azure to send from your Outlook address. Emails are currently being sent via the EPS master mailbox (Gmail fallback) instead." }),
703 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-amber-200/80 font-medium", children: [ 704 "To fix this, an admin of the ", 705 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-amber-300", children: "expertprotectionsvcs.com" }), 706 " Microsoft 365 tenant must grant admin consent for the ", 707 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-amber-300", children: "Mail.Send" }), 708 " Application permission in the Azure portal under the EPS Dashboard app registration." 709 ] }) 710 ] }) 711 ] }) }), 712 azureStatus === "sent_from_agent" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg bg-green-950/40 border border-green-700/50 p-3 flex items-start gap-2", children: [ 713 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-4 h-4 text-green-400 mt-0.5 shrink-0" }), 714 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-green-200/80", children: "Azure OAuth2 is working correctly â emails are sent directly from your Outlook address." }) 715 ] }),
716 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg bg-[#3C3B6E] border border-[#3C3B6E] p-3 flex items-center justify-between gap-3", children: [ 717 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm text-muted-foreground", children: [ 718 "Click ", 719 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-white", children: "Send Test Email" }), 720 " â a test message will be sent to your inbox within seconds." 721 ] }), 722 /* @__PURE__ */ jsxRuntimeExports.jsxs( 723 Button, 724 { 725 variant: "outline", 726 size: "sm", 727 onClick: () => testMutation.mutate({ agentKey }), 728 disabled: testMutation.isPending, 729 className: "border-[#3C3B6E] text-white hover:bg-[#3C3B6E] shrink-0", 730 children: [ 731 /* @__PURE__ */ jsxRuntimeExports.jsx(TestTubeDiagonal, { className: "w-3.5 h-3.5 mr-1.5" }), 732 testMutation.isPending ? "Sending..." : "Send Test Email" 733 ] 734 } 735 ) 736 ] }) 737 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
738 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "w-5 h-5 text-red-400" }), 739 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground", children: "No email connected. Enter your Microsoft 365 / Outlook email address below to connect." }) 740 ] }) }) 741 ] }), 742 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-[#2d2c5a] border-[#3C3B6E]", children: [ 743 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { children: [ 744 /* @__PURE__ */ jsxRuntimeExports.jsx(CardTitle, { className: "text-white text-base", children: isConnected ? "Update Outlook Email Address" : "Connect Your Microsoft 365 Email" }), 745 /* @__PURE__ */ jsxRuntimeExports.jsx(CardDescription, { children: "No App Password required. The EPS Dashboard uses secure Azure OAuth2 â just enter your Outlook email address and you're connected." }) 746 ] }), 747 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardContent, { className: "space-y-5", children: [ 748 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg bg-[#3C3B6E] border border-[#3C3B6E] p-4 space-y-2", children: [
749 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 750 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-4 h-4 text-blue-400" }), 751 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium text-white text-sm", children: "How this works" }) 752 ] }), 753 /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "text-sm text-muted-foreground space-y-1 list-disc list-inside", children: [ 754 /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: "Enter your Microsoft 365 / Outlook email address below" }), 755 /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [ 756 "The dashboard uses ", 757 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-white", children: "Azure OAuth2" }), 758 " â no password is ever stored" 759 ] }), 760 /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: "Emails are sent on your behalf via the EPS master mailbox (Greg Fay Insurance)" }),
761 /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [ 762 "Click ", 763 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-white", children: "Send Test Email" }), 764 " to confirm your inbox receives messages" 765 ] }), 766 /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: "You can disconnect at any time from this page" }) 767 ] }) 768 ] }), 769 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [ 770 /* @__PURE__ */ jsxRuntimeExports.jsx(Label, { className: "text-white", children: "Your Microsoft 365 / Outlook Email Address" }), 771 /* @__PURE__ */ jsxRuntimeExports.jsx( 772 Input, 773 { 774 type: "email", 775 placeholder: "[email protected]", 776 value: email, 777 onChange: (e) => setEmail(e.target.value), 778 className: "bg-[#3C3B6E] border-[#3C3B6E] text-white placeholder:text-muted-foreground" 779 } 780 ),
781 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Enter the same email address you use to log into Microsoft 365 / Outlook." }) 782 ] }), 783 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 pt-1", children: [ 784 /* @__PURE__ */ jsxRuntimeExports.jsxs( 785 Button, 786 { 787 onClick: handleSaveSmtp, 788 disabled: saveMutation.isPending, 789 className: "bg-[#B22234] hover:bg-[#b8973b] text-white font-semibold", 790 children: [ 791 /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { className: "w-4 h-4 mr-2" }), 792 saveMutation.isPending ? "Saving..." : isConnected ? "Update Email Address" : "Save & Connect" 793 ] 794 } 795 ), 796 isConnected && /* @__PURE__ */ jsxRuntimeExports.jsxs( 797 Button, 798 { 799 variant: "outline", 800 onClick: () => testMutation.mutate({ agentKey }), 801 disabled: testMutation.isPending, 802 className: "border-[#3C3B6E] text-white hover:bg-[#3C3B6E]", 803 children: [
804 /* @__PURE__ */ jsxRuntimeExports.jsx(TestTubeDiagonal, { className: "w-4 h-4 mr-2" }), 805 testMutation.isPending ? "Sending..." : "Send Test Email" 806 ] 807 } 808 ) 809 ] }) 810 ] }) 811 ] }), 812 /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-[#2d2c5a] border-[#3C3B6E]", children: [ 813 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "pb-3", children: [ 814 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 815 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardTitle, { className: "text-base text-white flex items-center gap-2", children: [ 816 /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { className: "w-4 h-4 text-[#B22234]" }), 817 "Google Review Email Preview" 818 ] }), 819 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1", children: [ 820 /* @__PURE__ */ jsxRuntimeExports.jsx( 821 "button", 822 { 823 onClick: () => setPreviewTab("request"), 824 className: `px-3 py-1 rounded text-xs font-medium transition-colors ${previewTab === "request" ? "bg-[#B22234] text-white" : "text-white/50 hover:text-white hover:bg-white/10"}`, 825 children: "Review Request" 826 } 827 ),
828 /* @__PURE__ */ jsxRuntimeExports.jsx( 829 "button", 830 { 831 onClick: () => setPreviewTab("reminder"), 832 className: `px-3 py-1 rounded text-xs font-medium transition-colors ${previewTab === "reminder" ? "bg-[#B22234] text-white" : "text-white/50 hover:text-white hover:bg-white/10"}`, 833 children: "Reminder" 834 } 835 ) 836 ] }) 837 ] }), 838 /* @__PURE__ */ jsxRuntimeExports.jsxs(CardDescription, { className: "text-white/50 text-xs mt-1", children: [ 839 "Exactly what your clients will receive â updates live as you edit your Google Review link above.", 840 previewData?.signatureName && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-green-400/80", children: [ 841 "Signature: ", 842 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-green-300", children: previewData.signatureName }) 843 ] }) 844 ] }) 845 ] }), 846 /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "pt-0", children: previewFetching ? /* @__P
846URE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center h-48 text-white/40 gap-2 text-sm", children: [ 847 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "w-4 h-4 animate-spin" }), 848 " Loading preview..." 849 ] }) : previewData ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-lg overflow-hidden border border-[#3C3B6E]", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 850 "iframe", 851 { 852 srcDoc: previewTab === "request" ? previewData.requestHtml : previewData.reminderHtml, 853 title: "Email preview", 854 sandbox: "allow-same-origin", 855 className: "w-full", 856 style: { height: "520px", border: "none", background: "#f4f6f9" } 857 }, 858 previewTab + (previewData.requestHtml?.length ?? 0) 859 ) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-48 text-white/40 text-sm", children: "Preview unavailable" }) }) 860 ] }), 861 /* @__PURE__ */ jsxRuntimeExports.jsx(GoogleCalendarCard, { agentKey }), 862 /* @__PURE__ */ jsxRuntimeExports.jsx(Card, { className: "bg-[#3C3B6E] border-[#3C3B6E]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "pt-4 pb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
863 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { className: "w-5 h-5 text-blue-400 mt-0.5 shrink-0" }), 864 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-muted-foreground space-y-1", children: [ 865 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium text-white", children: "Security & Privacy" }), 866 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [ 867 "This integration uses ", 868 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-white", children: "Microsoft Azure OAuth2" }), 869 " â the same enterprise-grade authentication used by Microsoft 365 apps. No passwords are stored. Access is managed by your IT administrator and can be revoked at any time from the Azure portal." 870 ] }), 871 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "You can disconnect your email at any time from this page. Disconnecting removes your email address from the dashboard immediately." }) 872 ] }) 873 ] }) }) }) 874 ] }); 875} 876 877export { AgentEmailSettings as default };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.