Skip to content
This repository was archived by the owner on Aug 14, 2025. It is now read-only.

Commit 3d0f995

Browse files
authored
Merge pull request #180 from notificationapi-com/KshTsj6I/3256-lovable-blog-5
Lovable tutorial
2 parents e2847a6 + 7e44e32 commit 3d0f995

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

docs/integrations/_category_.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"label": "Integrate With",
3+
"position": 4
4+
}

docs/integrations/lovable.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Lovable
2+
3+
## YouTube Walkthrough
4+
5+
import YouTubePlayer from '@site/src/components/YouTubePlayer';
6+
7+
<YouTubePlayer videoId="4VENlb0OuAw" title="Lovable Integration" />
8+
9+
<br />
10+
11+
In this tutorial, we'll learn how to send SMS and email notifications from your Lovable.dev application. We'll use NotificationAPI for sending notifications and Supabase edge functions to ensure secure implementation.
12+
13+
## Why Use Edge Functions for Notifications?
14+
15+
When implementing notifications in your application, it's crucial to handle sensitive operations like sending SMS or emails securely. Frontend code is visible to everyone and can be modified by malicious users. This is why we need to use backend services like Supabase edge functions (or a service of your choice) to handle these operations.
16+
17+
## Step 1: Set Up NotificationAPI
18+
19+
The setup is straightforward and only takes a minute.
20+
21+
## Step 2: Modify and give this prompt to Lovable
22+
23+
**Sample Prompt:**
24+
25+
```javascript
26+
// [WHEN X HAPPENS], send an SMS and Email notification [to recipient] using the following code from a Supabase edge function:
27+
28+
import notificationapi from 'notificationapi-node-server-sdk';
29+
30+
notificationapi.init('YOUR_CLIENT_ID', 'YOUR_CLIENT_SECRET');
31+
await notificationapi.send({
32+
type: 'alert', // type of notification
33+
to: {
34+
email: '[email protected]', // recipient's email
35+
number: '+15005550006' // recipient's number
36+
},
37+
email: {
38+
subject: 'New contact form submission received',
39+
html: '<p>New contact form submission received.</p>'
40+
},
41+
sms: {
42+
message: 'New contact form submission received.'
43+
}
44+
});
45+
```
46+
47+
- Replace [WHEN X HAPPENS] with the event that triggers the notification
48+
- Replace [to recipient] with who should receive the notification, possibly explaining how Lovable should retreive their email and phone number
49+
- If you have a back-end different from Supabase, replace the "a Supabase edge function"
50+
- Replace `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET` with your NotificationAPI credentials
51+
52+
## Security Best Practices
53+
54+
When implementing notifications, follow these security guidelines:
55+
56+
1. **Control Message Recipients**
57+
58+
- Either limit who can receive messages (e.g., only to your team)
59+
- Or control what the message says (use static templates)
60+
61+
2. **Never Trust User Input**
62+
63+
- If you include user-provided content in notification messages, bad actors can modify the message to send malicious content (spam, links to malicious sites, etc.)
64+
65+
3. **Implement Rate Limiting**
66+
- Add limits to how many notifications a user can trigger
67+
- Consider implementing user authentication for sensitive operations
68+
69+
Remember to always handle sensitive operations like sending notifications through backend services, never directly from the frontend.
70+
71+
## Feedback and support
72+
73+
If you have any questions or need help implementing notifications in your Lovable.dev application, feel free to reach out to us at [email protected]. We're here to help you create the best notification experience for your users.

src/components/YouTubePlayer.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import React, { useState } from 'react';
2+
3+
export default function YouTubePlayer({ videoId, title }) {
4+
const [isPlaying, setIsPlaying] = useState(false);
5+
const videoUrl = `https://www.youtube.com/embed/${videoId}`;
6+
7+
const handlePlay = () => {
8+
setIsPlaying(true);
9+
};
10+
11+
return (
12+
<div
13+
onClick={handlePlay}
14+
style={{
15+
position: 'relative',
16+
width: '100%',
17+
paddingTop: '56.25%', // 9/16 = 0.5625
18+
background: '#000',
19+
cursor: 'pointer'
20+
}}
21+
>
22+
{!isPlaying && (
23+
<div
24+
style={{
25+
position: 'absolute',
26+
top: 0,
27+
left: 0,
28+
width: '100%',
29+
height: '100%',
30+
display: 'flex',
31+
alignItems: 'center',
32+
justifyContent: 'center',
33+
background: 'rgba(0, 0, 0, 0.7)',
34+
zIndex: 1
35+
}}
36+
>
37+
<div
38+
style={{
39+
position: 'absolute',
40+
top: 0,
41+
left: 0,
42+
width: '100%',
43+
height: '100%',
44+
display: 'flex',
45+
alignItems: 'center',
46+
justifyContent: 'center',
47+
fontSize: '6rem',
48+
lineHeight: '1',
49+
fontWeight: 'bold',
50+
color: '#fff',
51+
textShadow:
52+
'0 0 100px rgba(255, 255, 255, 0.8), 0 0 40px rgba(255, 255, 255, 0.4)',
53+
textAlign: 'center',
54+
padding: '1rem',
55+
letterSpacing: '0.1em'
56+
}}
57+
>
58+
{title}
59+
</div>
60+
<div
61+
style={{
62+
width: '72px',
63+
height: '72px',
64+
background:
65+
'linear-gradient(0deg, rgba(255, 0, 0, 0.7) 0%, rgba(204, 0, 0, 0.7) 100%)',
66+
borderRadius: '50%',
67+
display: 'flex',
68+
alignItems: 'center',
69+
justifyContent: 'center',
70+
transition: 'all 0.2s ease',
71+
boxShadow:
72+
'0 2px 4px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.2)',
73+
zIndex: 2,
74+
backdropFilter: 'blur(2px)'
75+
}}
76+
onMouseOver={(e) => {
77+
e.currentTarget.style.transform = 'scale(1.1)';
78+
e.currentTarget.style.boxShadow =
79+
'0 4px 8px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.2)';
80+
}}
81+
onMouseOut={(e) => {
82+
e.currentTarget.style.transform = 'scale(1)';
83+
e.currentTarget.style.boxShadow =
84+
'0 2px 4px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.2)';
85+
}}
86+
>
87+
<div
88+
style={{
89+
width: 0,
90+
height: 0,
91+
borderStyle: 'solid',
92+
borderWidth: '14px 0 14px 24px',
93+
borderColor: 'transparent transparent transparent #ffffff',
94+
marginLeft: '4px',
95+
filter: 'drop-shadow(0 0 2px rgba(255, 255, 255, 0.5))'
96+
}}
97+
/>
98+
</div>
99+
</div>
100+
)}
101+
<iframe
102+
style={{
103+
position: 'absolute',
104+
top: 0,
105+
left: 0,
106+
width: '100%',
107+
height: '100%',
108+
display: isPlaying ? 'block' : 'none'
109+
}}
110+
src={isPlaying ? `${videoUrl}?autoplay=1` : videoUrl}
111+
title="YouTube video player"
112+
frameBorder="0"
113+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
114+
allowFullScreen
115+
/>
116+
</div>
117+
);
118+
}

0 commit comments

Comments
 (0)