Skip to content

Instantly share code, notes, and snippets.

@aberba
Created September 17, 2024 14:42
Show Gist options
  • Save aberba/a703857a6fc474122c9ebdfed6c7b3a8 to your computer and use it in GitHub Desktop.
Save aberba/a703857a6fc474122c9ebdfed6c7b3a8 to your computer and use it in GitHub Desktop.
Sapier clone
// pages/api/execute-zap.ts
import { NextApiRequest, NextApiResponse } from 'next'
// Simulated service actions
const serviceActions = {
gmail: {
'Send Email': async (data: any) => {
// Simulate sending an email
await new Promise(resolve => setTimeout(resolve, 1000))
return { success: true, message: `Email sent to ${data.to}` }
},
'Create Draft': async (data: any) => {
// Simulate creating a draft
await new Promise(resolve => setTimeout(resolve, 800))
return { success: true, message: `Draft created with subject: ${data.subject}` }
}
},
slack: {
'Send Message': async (data: any) => {
// Simulate sending a Slack message
await new Promise(resolve => setTimeout(resolve, 1200))
return { success: true, message: `Message sent to channel: ${data.channel}` }
},
'Create Channel': async (data: any) => {
// Simulate creating a Slack channel
await new Promise(resolve => setTimeout(resolve, 1500))
return { success: true, message: `Channel created: ${data.name}` }
}
},
trello: {
'Create Card': async (data: any) => {
// Simulate creating a Trello card
await new Promise(resolve => setTimeout(resolve, 900))
return { success: true, message: `Card created: ${data.title}` }
},
'Move Card': async (data: any) => {
// Simulate moving a Trello card
await new Promise(resolve => setTimeout(resolve, 700))
return { success: true, message: `Card moved to list: ${data.listName}` }
}
}
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { action } = req.body
if (!action || !action.service || !action.event) {
return res.status(400).json({ success: false, message: 'Invalid action data' })
}
try {
const serviceAction = serviceActions[action.service][action.event]
if (!serviceAction) {
return res.status(400).json({ success: false, message: 'Action not found' })
}
const result = await serviceAction(action.data || {})
res.status(200).json(result)
} catch (error) {
console.error('Error executing zap:', error)
res.status(500).json({ success: false, message: 'Error executing zap' })
}
} else {
res.setHeader('Allow', ['POST'])
res.status(405).end(`Method ${req.method} Not Allowed`)
}
}
import React, { useState } from 'react'
import { Button } from "@/components/ui/button"
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
import { CheckCircleIcon, XCircleIcon, LoaderIcon, MessageSquareIcon } from 'lucide-react'
import { Input } from "@/components/ui/input"
interface WorkflowStep {
id: number
name: string
status: 'pending' | 'in-progress' | 'completed' | 'failed'
duration: number
}
const initialWorkflow: WorkflowStep[] = [
{ id: 1, name: "Content Creation", status: 'pending', duration: 3000 },
{ id: 2, name: "AI-powered Proofreading", status: 'pending', duration: 2000 },
{ id: 3, name: "Human Review", status: 'pending', duration: 4000 },
{ id: 4, name: "Approval", status: 'pending', duration: 2000 },
{ id: 5, name: "SEO Optimization", status: 'pending', duration: 3000 },
{ id: 6, name: "Publish to CMS", status: 'pending', duration: 2000 },
{ id: 7, name: "Send SMS Notification", status: 'pending', duration: 1500 },
]
export default function AutomationWorkflow() {
const [workflow, setWorkflow] = useState<WorkflowStep[]>(initialWorkflow)
const [isRunning, setIsRunning] = useState(false)
const [phoneNumber, setPhoneNumber] = useState('')
const runWorkflow = async () => {
setIsRunning(true)
setWorkflow(initialWorkflow)
for (const step of workflow) {
setWorkflow(current =>
current.map(s => s.id === step.id ? { ...s, status: 'in-progress' } : s)
)
if (step.name === "Send SMS Notification") {
try {
const response = await fetch('/api/send-sms', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
to: phoneNumber,
body: 'Your content has been published successfully!',
}),
});
const result = await response.json();
if (result.success) {
setWorkflow(current =>
current.map(s => s.id === step.id ? { ...s, status: 'completed' } : s)
)
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Error sending SMS:', error);
setWorkflow(current =>
current.map(s => s.id === step.id ? { ...s, status: 'failed' } : s)
)
}
} else {
await new Promise<void>((resolve) => {
setTimeout(() => {
setWorkflow(current =>
current.map(s => s.id === step.id ? { ...s, status: Math.random() > 0.2 ? 'completed' : 'failed' } : s)
)
resolve()
}, step.duration)
})
}
if (step.status === 'failed') break
}
setIsRunning(false)
}
const getStatusIcon = (status: WorkflowStep['status'], name: string) => {
switch (status) {
case 'completed':
return <CheckCircleIcon className="h-5 w-5 text-green-500" />
case 'failed':
return <XCircleIcon className="h-5 w-5 text-red-500" />
case 'in-progress':
return <LoaderIcon className="h-5 w-5 text-blue-500 animate-spin" />
default:
return name === "Send SMS Notification" ?
<MessageSquareIcon className="h-5 w-5 text-gray-400" /> : null
}
}
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Content Publishing Automation Workflow</h1>
<div className="mb-4">
<Input
type="tel"
placeholder="Enter phone number for SMS"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)}
className="mb-2"
/>
<Button onClick={runWorkflow} disabled={isRunning || !phoneNumber}>
{isRunning ? 'Workflow Running...' : 'Start Workflow'}
</Button>
</div>
<div className="space-y-4">
{workflow.map((step) => (
<Card key={step.id} className={`${step.status === 'failed' ? 'border-red-500' : ''}`}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Step {step.id}: {step.name}
</CardTitle>
{getStatusIcon(step.status, step.name)}
</CardHeader>
<CardContent>
<div className="text-xs text-muted-foreground">
Status: {step.status.charAt(0).toUpperCase() + step.status.slice(1)}
</div>
{step.name === "Send SMS Notification" && step.status === 'completed' && (
<div className="text-xs text-green-600 mt-1">
SMS sent successfully!
</div>
)}
</CardContent>
</Card>
))}
</div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment