Skip to content

Commit 1c6ebfe

Browse files
committed
feat: add referall-widget pkg
1 parent 878b6a2 commit 1c6ebfe

21 files changed

Lines changed: 1089 additions & 0 deletions

packages/referral-widget/README.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# RefRef Widget
2+
3+
A customizable referral widget that can be easily embedded into any website.
4+
5+
## Installation
6+
7+
Add the following script tag to your HTML:
8+
9+
```html
10+
<script
11+
src="https://cdn.refref.io/widget.js"
12+
data-client-key="YOUR_CLIENT_KEY"
13+
></script>
14+
```
15+
16+
## Usage
17+
18+
### Basic Usage
19+
20+
The widget can be triggered in multiple ways:
21+
22+
1. Using a data attribute:
23+
24+
```html
25+
<button data-refref-trigger>Refer a Friend</button>
26+
```
27+
28+
2. Programmatically using the RefRef object:
29+
30+
```javascript
31+
// Open the widget
32+
window.RefRef.open();
33+
34+
// Close the widget
35+
window.RefRef.close();
36+
37+
// Toggle the widget
38+
window.RefRef.toggle();
39+
```
40+
41+
### Configuration
42+
43+
You can customize the widget's appearance and behavior:
44+
45+
```javascript
46+
window.RefRef.setConfig({
47+
appearance: {
48+
theme: "light", // or 'dark'
49+
primaryColor: "#4F46E5",
50+
position: "bottom-right", // 'bottom-left', 'top-right', 'top-left'
51+
buttonText: "Refer & Earn",
52+
widgetTitle: "Refer a Friend",
53+
},
54+
campaign: {
55+
id: "your-campaign-id",
56+
name: "Your Campaign Name",
57+
rewardType: "fixed", // or 'percentage'
58+
rewardAmount: 10,
59+
referralLink: "https://your-domain.com/ref/[CODE]",
60+
},
61+
sharing: {
62+
enabledChannels: ["email", "twitter", "facebook", "copy"],
63+
customMessage: "Check out this amazing product!",
64+
},
65+
});
66+
```
67+
68+
### Advanced: Pre-initialization Command Queue
69+
70+
You can queue commands before the widget script loads. This is useful for setting config or initializing with user data as soon as possible. The `init` call is used to associate the widget with a specific project and participant, and optionally a token for authentication. This enables personalized referral links and campaign tracking.
71+
72+
```html
73+
<script>
74+
window.RefRef = window.RefRef || [];
75+
window.RefRef.push([
76+
"setConfig",
77+
{
78+
appearance: { primaryColor: "#FF0000" },
79+
},
80+
]);
81+
window.RefRef.push([
82+
"init",
83+
{
84+
projectId: "my-project",
85+
participantId: "user123",
86+
},
87+
]);
88+
</script>
89+
<script
90+
async
91+
src="https://cdn.refref.io/widget.js"
92+
data-client-key="YOUR_CLIENT_KEY"
93+
></script>
94+
```
95+
96+
### Checking Widget State
97+
98+
```javascript
99+
// Check if the widget is open
100+
const isOpen = window.RefRef.isOpen;
101+
102+
// Get current configuration
103+
const config = window.RefRef.getConfig();
104+
```
105+
106+
### API Reference
107+
108+
- `window.RefRef.open()`: Open the widget.
109+
- `window.RefRef.close()`: Close the widget.
110+
- `window.RefRef.toggle()`: Toggle the widget open/closed.
111+
- `window.RefRef.setConfig(config)`: Update the widget configuration.
112+
- `window.RefRef.getConfig()`: Get the current widget configuration.
113+
- `window.RefRef.isOpen`: Boolean indicating if the widget is open.
114+
- `window.RefRef.init({ projectId, participantId, token? })`: (Optional) Programmatically initialize the widget with user/project info.
115+
Makes api call to load the config data.
116+
117+
#### `init` Method Details
118+
119+
The `init` method is used to associate the widget instance with a specific project and participant (user). This enables personalized referral links, campaign tracking, and secure widget initialization. It is especially useful if you want to dynamically set the user context after page load or in a single-page app.
120+
121+
**Parameters:**
122+
123+
- `projectId` (string, required): The unique identifier for your referral campaign or project.
124+
- `participantId` (string, required): The unique identifier for the current user or participant.
125+
- `token` (string, optional): An authentication token (e.g., JWT) if your API requires secure access.
126+
127+
**Usage Example:**
128+
129+
```javascript
130+
window.RefRef.init({
131+
projectId: "my-project-id",
132+
participantId: "user-123",
133+
token: "optional-jwt-token",
134+
});
135+
```
136+
137+
**What it does:**
138+
139+
- Makes a POST request to your backend to initialize the referral context.
140+
- Stores the referral link and user context in the widget state.
141+
- Enables personalized sharing and tracking for the participant.
142+
- If called before the widget script loads (via the command queue), initialization will occur as soon as the widget is ready.
143+
144+
## Development
145+
146+
1. Install dependencies:
147+
148+
```bash
149+
npm install
150+
```
151+
152+
2. Start development server:
153+
154+
```bash
155+
npm run dev
156+
```
157+
158+
3. Build for production:
159+
160+
```bash
161+
npm run build
162+
```
163+
164+
## Browser Support
165+
166+
The widget supports all modern browsers (Chrome, Firefox, Safari, Edge) and uses Shadow DOM for style isolation.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "",
8+
"css": "../../packages/ui/src/styles/globals.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true
11+
},
12+
"iconLibrary": "lucide",
13+
"aliases": {
14+
"components": "@/components",
15+
"hooks": "@/hooks",
16+
"lib": "@/lib",
17+
"utils": "@refref/ui/lib/utils",
18+
"ui": "@refref/ui/components"
19+
}
20+
}

packages/referral-widget/demo.html

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>RefRef Widget Demo</title>
7+
<!-- Include the RefRef Widget -->
8+
<script
9+
src="./dist/referral-widget.es.js"
10+
data-client-key="YOUR_CLIENT_KEY"
11+
></script>
12+
<style>
13+
body {
14+
font-family:
15+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
16+
max-width: 800px;
17+
margin: 0 auto;
18+
padding: 20px;
19+
line-height: 1.6;
20+
}
21+
.demo-section {
22+
margin: 40px 0;
23+
padding: 20px;
24+
border: 1px solid #e5e7eb;
25+
border-radius: 8px;
26+
}
27+
button {
28+
padding: 10px 20px;
29+
border: none;
30+
border-radius: 6px;
31+
background: #4f46e5;
32+
color: white;
33+
cursor: pointer;
34+
margin: 10px 0;
35+
}
36+
button:hover {
37+
background: #4338ca;
38+
}
39+
pre {
40+
background: #f5f5f5;
41+
padding: 15px;
42+
border-radius: 6px;
43+
overflow-x: auto;
44+
}
45+
</style>
46+
</head>
47+
<body>
48+
<h1>RefRef Widget Demo</h1>
49+
50+
<div class="demo-section">
51+
<h2>Basic Usage</h2>
52+
<p>Click the button below to open the widget (using data attribute):</p>
53+
<button data-refref-trigger>Open Widget (Data Attribute)</button>
54+
55+
<p>Or use the programmatic API:</p>
56+
<button onclick="window.RefRef.open()">Open Widget (JavaScript)</button>
57+
<button onclick="window.RefRef.close()">Close Widget</button>
58+
<button onclick="window.RefRef.toggle()">Toggle Widget</button>
59+
</div>
60+
61+
<div class="demo-section">
62+
<h2>Widget Configuration</h2>
63+
<p>Try different configurations:</p>
64+
<button onclick="applyLightTheme()">Light Theme</button>
65+
<button onclick="applyDarkTheme()">Dark Theme</button>
66+
<button onclick="changePosition()">Change Position</button>
67+
</div>
68+
69+
<div class="demo-section">
70+
<h2>Event Handling</h2>
71+
<pre id="eventLog">Events will be logged here...</pre>
72+
</div>
73+
74+
<script type="module">
75+
// Initialize event logging
76+
const eventLog = document.getElementById("eventLog");
77+
function logEvent(message) {
78+
const timestamp = new Date().toLocaleTimeString();
79+
eventLog.textContent =
80+
`[${timestamp}] ${message}\n` + eventLog.textContent;
81+
}
82+
83+
// Theme configuration functions
84+
window.applyLightTheme = () => {
85+
window.RefRef.setConfig({
86+
appearance: {
87+
theme: "light",
88+
primaryColor: "#4F46E5",
89+
buttonText: "Refer a Friend (Light)",
90+
widgetTitle: "Light Theme Widget",
91+
},
92+
});
93+
};
94+
95+
window.applyDarkTheme = () => {
96+
window.RefRef.setConfig({
97+
appearance: {
98+
theme: "dark",
99+
primaryColor: "#818CF8",
100+
buttonText: "Refer a Friend (Dark)",
101+
widgetTitle: "Dark Theme Widget",
102+
},
103+
});
104+
};
105+
106+
let currentPosition = 0;
107+
const positions = [
108+
"bottom-right",
109+
"bottom-left",
110+
"top-right",
111+
"top-left",
112+
];
113+
114+
window.changePosition = () => {
115+
currentPosition = (currentPosition + 1) % positions.length;
116+
window.RefRef.setConfig({
117+
appearance: {
118+
position: positions[currentPosition],
119+
},
120+
});
121+
logEvent(`Widget position changed to: ${positions[currentPosition]}`);
122+
};
123+
124+
// Set initial configuration
125+
window.RefRef.setConfig({
126+
appearance: {
127+
theme: "light",
128+
primaryColor: "#4F46E5",
129+
position: "bottom-right",
130+
buttonText: "Refer & Earn",
131+
widgetTitle: "Refer a Friend",
132+
},
133+
campaign: {
134+
id: "demo-campaign",
135+
name: "Demo Campaign",
136+
rewardType: "fixed",
137+
rewardAmount: 25,
138+
referralLink: "https://example.com/ref/[CODE]",
139+
},
140+
sharing: {
141+
enabledChannels: ["email", "twitter", "facebook", "copy"],
142+
customMessage:
143+
"Check out this amazing product! Use my referral link to get started:",
144+
},
145+
});
146+
</script>
147+
</body>
148+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { config } from "@refref/eslint-config/react-internal";
2+
3+
/** @type {import("eslint").Linter.Config} */
4+
export default config;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + React + TS</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

0 commit comments

Comments
 (0)