-
🔗
+
{data.config.method || 'POST'} {data.config.url}
@@ -453,7 +467,7 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
target: transition.toStepId,
type: 'smoothstep',
animated: step.type === 'DELAY' || step.type === 'WAIT_FOR_EVENT',
- label: isConditional ? (branch === 'yes' ? '✓ Yes' : '✗ No') : undefined,
+ label: isConditional ? (branch === 'yes' ? 'Yes' : 'No') : undefined,
labelStyle: {
fill: branch === 'yes' ? '#16a34a' : branch === 'no' ? '#dc2626' : '#64748b',
fontWeight: 600,
@@ -498,7 +512,7 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
target: `${step.id}-add-yes`,
type: 'smoothstep',
animated: false,
- label: '✓ Yes',
+ label: 'Yes',
labelStyle: {fill: '#16a34a', fontWeight: 600, fontSize: 12},
labelBgStyle: {fill: '#fff', fillOpacity: 0.95},
labelBgPadding: [8, 4] as [number, number],
@@ -515,7 +529,7 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
target: `${step.id}-add-no`,
type: 'smoothstep',
animated: false,
- label: '✗ No',
+ label: 'No',
labelStyle: {fill: '#dc2626', fontWeight: 600, fontSize: 12},
labelBgStyle: {fill: '#fff', fillOpacity: 0.95},
labelBgPadding: [8, 4] as [number, number],
@@ -775,7 +789,7 @@ export function WorkflowBuilder({workflowId, steps, onUpdate}: WorkflowBuilderPr
className="bg-blue-50 border border-blue-200 px-4 py-2.5 rounded-lg shadow-lg"
>
- 💡
+
Click the + buttons to add and connect steps!
diff --git a/apps/web/src/components/WorkflowVisualizer.tsx b/apps/web/src/components/WorkflowVisualizer.tsx
index 2ab599d..2358df5 100644
--- a/apps/web/src/components/WorkflowVisualizer.tsx
+++ b/apps/web/src/components/WorkflowVisualizer.tsx
@@ -14,7 +14,7 @@ import {
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import type {WorkflowStep} from '@plunk/db';
-import {Clock, GitBranch, LogOut, Mail, UserCog, Webhook} from 'lucide-react';
+import {AlertTriangle, Clock, GitBranch, Hourglass, Link, LogOut, Mail, Timer, UserCog, Webhook} from 'lucide-react';
import {useEffect, useMemo} from 'react';
import dagre from 'dagre';
@@ -176,7 +176,7 @@ function CustomNode({
{data.template && (
- 📧
+
{data.template.name}
@@ -184,7 +184,7 @@ function CustomNode({
{data.type === 'DELAY' && data.config?.amount && (
-
⏱️
+
Wait {data.config.amount} {data.config.unit}
@@ -193,15 +193,16 @@ function CustomNode({
)}
{data.type === 'CONDITION' && (
-
-
🔀 If/Else Branch
+
+
+ If/Else Branch
)}
{data.type === 'WAIT_FOR_EVENT' && data.config?.eventName && (
- ⏳
+
{data.config.eventName}
@@ -209,7 +210,7 @@ function CustomNode({
{data.type === 'WEBHOOK' && data.config?.url && (
- 🔗
+
{data.config.method || 'POST'}
@@ -333,7 +334,7 @@ export function WorkflowVisualizer({steps}: WorkflowVisualizerProps) {
target: transition.toStepId,
type: 'smoothstep',
animated: false,
- label: isConditional ? (branch === 'yes' ? '✓ Yes' : '✗ No') : undefined,
+ label: isConditional ? (branch === 'yes' ? 'Yes' : 'No') : undefined,
labelStyle: {
fill: branch === 'yes' ? '#16a34a' : branch === 'no' ? '#dc2626' : '#64748b',
fontWeight: 600,
@@ -376,7 +377,7 @@ export function WorkflowVisualizer({steps}: WorkflowVisualizerProps) {
target: `${step.id}-yes-end`,
type: 'smoothstep',
animated: false,
- label: '✓ Yes',
+ label: 'Yes',
labelStyle: {
fill: '#16a34a',
fontWeight: 600,
@@ -409,7 +410,7 @@ export function WorkflowVisualizer({steps}: WorkflowVisualizerProps) {
target: `${step.id}-no-end`,
type: 'smoothstep',
animated: false,
- label: '✗ No',
+ label: 'No',
labelStyle: {
fill: '#dc2626',
fontWeight: 600,
@@ -518,7 +519,7 @@ export function WorkflowVisualizer({steps}: WorkflowVisualizerProps) {
className="bg-amber-50 border border-amber-200 px-4 py-2.5 rounded-lg shadow-lg"
>
-
⚠️
+
No transitions found. Connect your steps to see the flow.
diff --git a/apps/web/src/pages/campaigns/[id].tsx b/apps/web/src/pages/campaigns/[id].tsx
index 5729cad..172c71a 100644
--- a/apps/web/src/pages/campaigns/[id].tsx
+++ b/apps/web/src/pages/campaigns/[id].tsx
@@ -23,6 +23,7 @@ import {
Select,
SelectContent,
SelectItem,
+ SelectItemWithDescription,
SelectTrigger,
SelectValue,
StickySaveBar
@@ -343,20 +344,36 @@ export default function CampaignDetailsPage() {
{c.name}
Draft
-
Make changes to your campaign before sending
+
+ Make changes to your campaign before sending
+
- {!hasChanges && !isSubmitting && All changes saved}
- {hasChanges && !isSubmitting && Unsaved changes}
+ {!hasChanges && !isSubmitting && (
+ All changes saved
+ )}
+ {hasChanges && !isSubmitting && (
+ Unsaved changes
+ )}
-
@@ -499,9 +528,12 @@ export default function CampaignDetailsPage() {
{segments &&
segments.length > 0 &&
segments.map(segment => (
-
- {segment.name} ({segment.memberCount.toLocaleString()} contacts)
-
+
))}
diff --git a/apps/web/src/pages/campaigns/create.tsx b/apps/web/src/pages/campaigns/create.tsx
index e0a1592..edcac9c 100644
--- a/apps/web/src/pages/campaigns/create.tsx
+++ b/apps/web/src/pages/campaigns/create.tsx
@@ -9,9 +9,9 @@ import {
Label,
Select,
SelectContent,
- SelectItem,
+ SelectItemWithDescription,
SelectTrigger,
- SelectValue,
+ SelectValue
} from '@plunk/ui';
import type {Segment} from '@plunk/db';
import {CampaignAudienceType} from '@plunk/db';
@@ -93,269 +93,286 @@ export default function CreateCampaignPage() {
return (
<>
-
-
- {/* Header */}
-
-
-
-
-
-
-
-
Create Campaign
-
Create a new email campaign to send to your contacts
+
+
+ {/* Header */}
+
+
+
+
+
+
+
+
Create Campaign
+
+ Create a new email campaign to send to your contacts
+
+
-
- {/* Form */}
-