Skip to content

Commit

Permalink
post to telegram
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotBraem committed Dec 22, 2024
1 parent 93fb718 commit fe3a4f6
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel
Expand Down
55 changes: 55 additions & 0 deletions api/send-telegram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { VercelRequest, VercelResponse } from '@vercel/node';

export default async function handler(
req: VercelRequest,
res: VercelResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}

try {
const { projectName, description, timeline, customTimeline, contact } = req.body;

// Validate required fields
if (!projectName || !description || !contact || !(timeline || customTimeline)) {
return res.status(400).json({ message: 'Missing required fields' });
}

// Format message for Telegram
const message = `
🚀 New Project Request
📋 Project Name: ${projectName}
📝 Description: ${description}
⏰ Timeline: ${timeline === 'custom' ? customTimeline : timeline}
📧 Contact: ${contact}
`;

// Send to Telegram
const response = await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
chat_id: process.env.TELEGRAM_CHANNEL_ID,
text: message,
parse_mode: 'HTML',
}),
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.description || 'Failed to send message to Telegram');
}

return res.status(200).json({ message: 'Project request sent successfully' });
} catch (error) {
console.error('Error sending to Telegram:', error);
return res.status(500).json({ message: 'Error sending project request' });
}
}
Binary file modified bun.lockb
Binary file not shown.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,26 @@
},
"dependencies": {
"lucide-react": "^0.344.0",
"nodemailer": "^6.9.16",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.22.3"
},
"devDependencies": {
"@eslint/js": "^9.9.1",
"@playwright/test": "^1.46.1",
"@types/node": "^20.11.0",
"prettier": "^3.3.3",
"@eslint/js": "^9.9.1",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"@vercel/node": "^5.0.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.18",
"eslint": "^9.9.1",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11",
"globals": "^15.9.0",
"postcss": "^8.4.35",
"prettier": "^3.3.3",
"tailwindcss": "^3.4.1",
"typescript": "^5.5.3",
"typescript-eslint": "^8.3.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function Navigation() {
<div className="flex items-center justify-between">
<Link to="/" className="flex items-center gap-2">
<HardHat size={32} className="text-yellow-400" />
<span className="text-xl font-bold text-white">Build DAO</span>
{/* <span className="text-xl font-bold text-white">Build DAO</span> */}
</Link>

<div className="flex items-center gap-8">
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Process.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ export default function Process() {
<div className="flex-1">
<div className="flex items-center justify-between mb-2">
<h3 className="text-xl font-semibold">{step.title}</h3>
<span className="text-sm text-yellow-400 bg-yellow-400/10 px-3 py-1 rounded-full">
{/* <span className="text-sm text-yellow-400 bg-yellow-400/10 px-3 py-1 rounded-full">
{step.duration}
</span>
</span> */}
</div>
<p className="text-gray-300">{step.description}</p>
</div>
Expand Down
122 changes: 109 additions & 13 deletions src/pages/SubmitProject.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,76 @@
import { ArrowLeft, CheckCircle, Clock, Rocket } from "lucide-react";
import { Link } from "react-router-dom";
import { useState, FormEvent } from "react";

interface FormData {
projectName: string;
description: string;
timeline: string;
customTimeline: string;
contact: string;
}

export default function SubmitProject() {
const [formData, setFormData] = useState<FormData>({
customTimeline: "",
projectName: "",
description: "",
timeline: "",
contact: ""
});

const [isSubmitting, setIsSubmitting] = useState(false);

const handleSubmit = async (e: FormEvent) => {
e.preventDefault();

// Basic validation
if (!formData.projectName || !formData.description || !formData.contact ||
(formData.timeline === 'custom' ? !formData.customTimeline : !formData.timeline)) {
alert("Please fill in all fields");
return;
}

try {
setIsSubmitting(true);
const response = await fetch('/api/send-telegram', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'Failed to send contact');
}

// Clear form on success
setFormData({
projectName: "",
description: "",
timeline: "",
customTimeline: "",
contact: ""
});

alert('Project submitted successfully! We will get back to you soon.');
} catch (error) {
alert(error instanceof Error ? error.message : 'Failed to submit project. Please try again.');
} finally {
setIsSubmitting(false);
}
};

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};

return (
<div className="min-h-screen bg-gray-900 text-white py-16">
<div className="container mx-auto px-6">
Expand All @@ -21,13 +90,16 @@ export default function SubmitProject() {
our team will get back to you within 24 hours.
</p>

<form className="space-y-6">
<form className="space-y-6" onSubmit={handleSubmit}>
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Project Name
</label>
<input
type="text"
name="projectName"
value={formData.projectName}
onChange={handleInputChange}
className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white"
placeholder="Enter your project name"
/>
Expand All @@ -39,6 +111,9 @@ export default function SubmitProject() {
</label>
<textarea
rows={4}
name="description"
value={formData.description}
onChange={handleInputChange}
className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white"
placeholder="Describe your project and its goals"
/>
Expand All @@ -48,31 +123,52 @@ export default function SubmitProject() {
<label className="block text-sm font-medium text-gray-300 mb-2">
Timeline
</label>
<select className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white">
<select
name="timeline"
value={formData.timeline}
onChange={handleInputChange}
className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white mb-2"
>
<option value="">Select desired timeline</option>
<option value="2-weeks">2 weeks</option>
<option value="4-weeks">4 weeks</option>
<option value="6-weeks">6 weeks</option>
<option value="3-days">3 days</option>
<option value="1-week">1 week</option>
<option value="1-month">1 month</option>
<option value="custom">Custom timeline</option>
</select>
{formData.timeline === 'custom' && (
<input
type="text"
name="customTimeline"
value={formData.customTimeline}
onChange={handleInputChange}
className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white"
placeholder="Enter your desired timeline"
/>
)}
</div>

<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Contact Email
Contact
</label>
<input
type="email"
type="contact"
name="contact"
value={formData.contact}
onChange={handleInputChange}
className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg focus:outline-none focus:border-yellow-400 text-white"
placeholder="Enter your email"
placeholder="Enter your contact, e.g. email, telegram"
/>
</div>

<button
type="submit"
className="w-full py-4 bg-gradient-to-r from-yellow-400 to-orange-500 rounded-lg font-semibold text-gray-900 hover:opacity-90 transition-opacity"
disabled={isSubmitting}
className={`w-full py-4 bg-gradient-to-r from-yellow-400 to-orange-500 rounded-lg font-semibold text-gray-900 hover:opacity-90 transition-opacity ${
isSubmitting ? 'opacity-50 cursor-not-allowed' : ''
}`}
>
Submit Project
{isSubmitting ? 'Submitting...' : 'Submit Project'}
</button>
</form>
</div>
Expand All @@ -88,7 +184,7 @@ export default function SubmitProject() {
<div>
<h3 className="font-semibold mb-2">Fast Turnaround</h3>
<p className="text-gray-300">
Most MVPs are delivered within 2-4 weeks
Most MVPs are delivered in under 1 week
</p>
</div>
</div>
Expand Down Expand Up @@ -116,7 +212,7 @@ export default function SubmitProject() {
</div>
</div>

<div className="bg-gray-800/50 p-8 rounded-xl">
{/* <div className="bg-gray-800/50 p-8 rounded-xl">
<h2 className="text-2xl font-semibold mb-4">
Recent Success Stories
</h2>
Expand All @@ -140,7 +236,7 @@ export default function SubmitProject() {
</footer>
</blockquote>
</div>
</div>
</div> */}
</div>
</div>
</div>
Expand Down
9 changes: 9 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": 2,
"functions": {
"api/send-telegram.ts": {
"memory": 1024,
"maxDuration": 10
}
}
}

0 comments on commit fe3a4f6

Please sign in to comment.