Skip to content

Commit 686b212

Browse files
Add plugin infrastructure
Return to implementing the plugin infrastructure, deferring security configuration. This involves setting up API endpoints for WordPress and Shopify, and a mechanism for generating API keys for plugins.
1 parent ba06730 commit 686b212

3 files changed

Lines changed: 221 additions & 32 deletions

File tree

api/wordpress-config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Proxy pour les Firebase Functions depuis Vercel
2+
export default async function handler(req, res) {
3+
if (req.method !== 'POST') {
4+
return res.status(405).json({ error: 'Method not allowed' });
5+
}
6+
7+
try {
8+
// Forward la requête vers Firebase Functions
9+
const firebaseUrl = 'https://us-central1-refspring-project.cloudfunctions.net/wordpressConfig';
10+
11+
const response = await fetch(firebaseUrl, {
12+
method: 'POST',
13+
headers: {
14+
'Content-Type': 'application/json',
15+
},
16+
body: JSON.stringify(req.body)
17+
});
18+
19+
const data = await response.json();
20+
21+
if (!response.ok) {
22+
return res.status(response.status).json(data);
23+
}
24+
25+
res.json(data);
26+
} catch (error) {
27+
console.error('Proxy error:', error);
28+
res.status(500).json({ error: 'Internal server error' });
29+
}
30+
}

src/components/plugins/PluginManager.tsx

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
33
import { Button } from '@/components/ui/button';
44
import { Input } from '@/components/ui/input';
@@ -8,6 +8,8 @@ import { Badge } from '@/components/ui/badge';
88
import { useToast } from '@/hooks/use-toast';
99
import { Globe, ShoppingBag, Key, Copy, ExternalLink } from 'lucide-react';
1010
import { CopyButton } from '@/components/CopyButton';
11+
import { httpsCallable } from 'firebase/functions';
12+
import { functions } from '@/lib/firebase';
1113

1214
interface PluginManagerProps {
1315
campaignId: string;
@@ -36,14 +38,17 @@ export const PluginManager: React.FC<PluginManagerProps> = ({ campaignId, userId
3638
const generateApiKey = async () => {
3739
setIsLoading(true);
3840
try {
39-
// Simuler l'appel à la fonction Firebase
40-
const newApiKey = 'rsp_' + Buffer.from(campaignId + '_' + Date.now()).toString('base64').slice(0, 32);
41-
setApiKey(newApiKey);
41+
const generatePluginApiKey = httpsCallable(functions, 'generatePluginApiKey');
42+
const result = await generatePluginApiKey({ campaignId });
43+
const data = result.data as { apiKey: string };
44+
45+
setApiKey(data.apiKey);
4246
toast({
4347
title: "Clé API générée",
4448
description: "Votre clé API a été créée avec succès",
4549
});
4650
} catch (error) {
51+
console.error('Erreur génération clé API:', error);
4752
toast({
4853
title: "Erreur",
4954
description: "Impossible de générer la clé API",
@@ -64,50 +69,59 @@ export const PluginManager: React.FC<PluginManagerProps> = ({ campaignId, userId
6469
return;
6570
}
6671

72+
if (!apiKey) {
73+
toast({
74+
title: "Erreur",
75+
description: "Veuillez d'abord générer une clé API",
76+
variant: "destructive"
77+
});
78+
return;
79+
}
80+
6781
setIsLoading(true);
6882
try {
69-
// Simuler l'appel à l'API WordPress
70-
const script = `<?php
71-
// RefSpring Tracking Script for WordPress
72-
function refspring_add_tracking_script() {
73-
$campaign_id = '${campaignId}';
74-
$script_url = 'https://refspring.com/tracking.js';
75-
76-
echo '<script data-campaign="' . $campaign_id . '" src="' . $script_url . '"></script>';
77-
}
78-
add_action('wp_head', 'refspring_add_tracking_script');
83+
const response = await fetch('/api/wordpress-config', {
84+
method: 'POST',
85+
headers: {
86+
'Content-Type': 'application/json',
87+
},
88+
body: JSON.stringify({
89+
pluginType: 'wordpress',
90+
domain: wordpressDomain,
91+
apiKey,
92+
campaignId,
93+
userId,
94+
settings: {
95+
autoInject: true,
96+
trackingEnabled: true
97+
}
98+
})
99+
});
79100

80-
// Hook pour WooCommerce conversions
81-
function refspring_woocommerce_conversion($order_id) {
82-
$order = wc_get_order($order_id);
83-
$total = $order->get_total();
84-
85-
echo '<script>
86-
if (window.RefSpring) {
87-
window.RefSpring.trackConversion(' . $total . ');
88-
}
89-
</script>';
90-
}
91-
add_action('woocommerce_thankyou', 'refspring_woocommerce_conversion');
92-
?>`;
101+
if (!response.ok) {
102+
throw new Error('Configuration failed');
103+
}
93104

94-
setTrackingScript(script);
105+
const result = await response.json();
106+
setTrackingScript(result.trackingScript);
95107

96108
const newConfig: PluginConfig = {
97-
id: 'wp_' + Date.now(),
109+
id: result.pluginId,
98110
type: 'wordpress',
99111
domain: wordpressDomain,
100112
active: true,
101113
createdAt: new Date()
102114
};
103115

104116
setConfigs([...configs, newConfig]);
117+
setWordpressDomain('');
105118

106119
toast({
107120
title: "WordPress configuré",
108121
description: "Le plugin WordPress a été configuré avec succès",
109122
});
110123
} catch (error) {
124+
console.error('Erreur configuration WordPress:', error);
111125
toast({
112126
title: "Erreur",
113127
description: "Impossible de configurer WordPress",
@@ -128,19 +142,42 @@ add_action('woocommerce_thankyou', 'refspring_woocommerce_conversion');
128142
return;
129143
}
130144

145+
if (!apiKey) {
146+
toast({
147+
title: "Erreur",
148+
description: "Veuillez d'abord générer une clé API",
149+
variant: "destructive"
150+
});
151+
return;
152+
}
153+
131154
setIsLoading(true);
132155
try {
133-
// Simuler l'installation Shopify
134-
const shopifyUrl = `https://${shopifyShop}.myshopify.com/admin/oauth/authorize?client_id=YOUR_APP_ID&scope=read_orders,write_script_tags&redirect_uri=https://refspring.com/shopify/callback&state=${campaignId}`;
156+
// Générer l'URL d'autorisation Shopify avec l'état nécessaire
157+
const state = btoa(JSON.stringify({ campaignId, userId, apiKey }));
158+
const shopifyUrl = `https://${shopifyShop}.myshopify.com/admin/oauth/authorize?client_id=YOUR_SHOPIFY_APP_ID&scope=read_orders,write_script_tags&redirect_uri=https://refspring.com/shopify/callback&state=${state}`;
135159

136160
// Ouvrir dans une nouvelle fenêtre
137161
window.open(shopifyUrl, '_blank');
138162

163+
// Simuler l'ajout de la configuration en attendant le callback
164+
const newConfig: PluginConfig = {
165+
id: 'shopify_' + Date.now(),
166+
type: 'shopify',
167+
domain: shopifyShop + '.myshopify.com',
168+
active: false, // Sera activé après autorisation
169+
createdAt: new Date()
170+
};
171+
172+
setConfigs([...configs, newConfig]);
173+
setShopifyShop('');
174+
139175
toast({
140176
title: "Redirection Shopify",
141-
description: "Vous allez être redirigé vers Shopify pour autoriser l'application",
177+
description: "Autorisez l'application dans la nouvelle fenêtre pour terminer l'installation",
142178
});
143179
} catch (error) {
180+
console.error('Erreur configuration Shopify:', error);
144181
toast({
145182
title: "Erreur",
146183
description: "Impossible de configurer Shopify",

src/hooks/usePluginIntegration.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { useState, useCallback } from 'react';
2+
import { httpsCallable } from 'firebase/functions';
3+
import { functions } from '@/lib/firebase';
4+
import { useToast } from '@/hooks/use-toast';
5+
6+
interface PluginConfig {
7+
id: string;
8+
type: 'wordpress' | 'shopify';
9+
domain: string;
10+
active: boolean;
11+
createdAt: Date;
12+
}
13+
14+
export const usePluginIntegration = (campaignId: string, userId: string) => {
15+
const [configs, setConfigs] = useState<PluginConfig[]>([]);
16+
const [apiKey, setApiKey] = useState<string>('');
17+
const [isLoading, setIsLoading] = useState(false);
18+
const { toast } = useToast();
19+
20+
const generateApiKey = useCallback(async () => {
21+
setIsLoading(true);
22+
try {
23+
const generatePluginApiKey = httpsCallable(functions, 'generatePluginApiKey');
24+
const result = await generatePluginApiKey({ campaignId });
25+
const data = result.data as { apiKey: string };
26+
27+
setApiKey(data.apiKey);
28+
return data.apiKey;
29+
} catch (error) {
30+
console.error('Erreur génération clé API:', error);
31+
toast({
32+
title: "Erreur",
33+
description: "Impossible de générer la clé API",
34+
variant: "destructive"
35+
});
36+
throw error;
37+
} finally {
38+
setIsLoading(false);
39+
}
40+
}, [campaignId, toast]);
41+
42+
const configureWordPress = useCallback(async (domain: string) => {
43+
if (!apiKey) {
44+
throw new Error('API key required');
45+
}
46+
47+
setIsLoading(true);
48+
try {
49+
const response = await fetch('/api/wordpress-config', {
50+
method: 'POST',
51+
headers: {
52+
'Content-Type': 'application/json',
53+
},
54+
body: JSON.stringify({
55+
pluginType: 'wordpress',
56+
domain,
57+
apiKey,
58+
campaignId,
59+
userId,
60+
settings: {
61+
autoInject: true,
62+
trackingEnabled: true
63+
}
64+
})
65+
});
66+
67+
if (!response.ok) {
68+
throw new Error('Configuration failed');
69+
}
70+
71+
const result = await response.json();
72+
73+
const newConfig: PluginConfig = {
74+
id: result.pluginId,
75+
type: 'wordpress',
76+
domain,
77+
active: true,
78+
createdAt: new Date()
79+
};
80+
81+
setConfigs(prev => [...prev, newConfig]);
82+
return result.trackingScript;
83+
} catch (error) {
84+
console.error('Erreur configuration WordPress:', error);
85+
throw error;
86+
} finally {
87+
setIsLoading(false);
88+
}
89+
}, [apiKey, campaignId, userId]);
90+
91+
const configureShopify = useCallback(async (shop: string) => {
92+
if (!apiKey) {
93+
throw new Error('API key required');
94+
}
95+
96+
// Générer l'URL d'autorisation Shopify
97+
const state = btoa(JSON.stringify({ campaignId, userId, apiKey }));
98+
const shopifyUrl = `https://${shop}.myshopify.com/admin/oauth/authorize?client_id=YOUR_SHOPIFY_APP_ID&scope=read_orders,write_script_tags&redirect_uri=https://refspring.com/shopify/callback&state=${state}`;
99+
100+
// Ajouter une configuration en attente
101+
const newConfig: PluginConfig = {
102+
id: 'shopify_' + Date.now(),
103+
type: 'shopify',
104+
domain: shop + '.myshopify.com',
105+
active: false,
106+
createdAt: new Date()
107+
};
108+
109+
setConfigs(prev => [...prev, newConfig]);
110+
111+
return shopifyUrl;
112+
}, [apiKey, campaignId, userId]);
113+
114+
return {
115+
configs,
116+
apiKey,
117+
isLoading,
118+
generateApiKey,
119+
configureWordPress,
120+
configureShopify
121+
};
122+
};

0 commit comments

Comments
 (0)