|
|
@@ -6,9 +6,11 @@ import { Input } from "@/components/ui/input";
|
|
|
import { Label } from "@/components/ui/label";
|
|
|
import { Switch } from "@/components/ui/switch";
|
|
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
|
|
-import { Plus, Settings, Store, Bot, PhoneCall, Globe, Zap, ShoppingBag, Loader2 } from "lucide-react";
|
|
|
+import { Plus, Settings, Store, Bot, PhoneCall, Globe, Zap, ShoppingBag, Loader2, Trash2, Info } from "lucide-react";
|
|
|
import { ShopRenterConnect } from "./ShopRenterConnect";
|
|
|
+import { WooCommerceConnect } from "./WooCommerceConnect";
|
|
|
import { API_URL } from "@/lib/config";
|
|
|
+import { useToast } from "@/hooks/use-toast";
|
|
|
|
|
|
interface ConnectedStore {
|
|
|
id: string;
|
|
|
@@ -18,6 +20,13 @@ interface ConnectedStore {
|
|
|
is_active: boolean | null;
|
|
|
phone_number: string | null;
|
|
|
created_at: string | null;
|
|
|
+ alt_data?: {
|
|
|
+ wcVersion?: string;
|
|
|
+ wpVersion?: string;
|
|
|
+ apiVersion?: string;
|
|
|
+ connectedAt?: string;
|
|
|
+ [key: string]: any;
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
export function IntegrationsContent() {
|
|
|
@@ -25,38 +34,80 @@ export function IntegrationsContent() {
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
const [showConnectDialog, setShowConnectDialog] = useState(false);
|
|
|
const [selectedPlatform, setSelectedPlatform] = useState<string | null>(null);
|
|
|
+ const { toast } = useToast();
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- const fetchStores = async () => {
|
|
|
- try {
|
|
|
- const sessionData = localStorage.getItem('session_data');
|
|
|
- if (!sessionData) {
|
|
|
- throw new Error('No session data found');
|
|
|
- }
|
|
|
-
|
|
|
- const session = JSON.parse(sessionData);
|
|
|
- const response = await fetch(`${API_URL}/api/stores`, {
|
|
|
- headers: {
|
|
|
- 'Authorization': `Bearer ${session.access_token}`,
|
|
|
- 'Content-Type': 'application/json'
|
|
|
- }
|
|
|
- });
|
|
|
+ const fetchStores = async () => {
|
|
|
+ try {
|
|
|
+ const sessionData = localStorage.getItem('session_data');
|
|
|
+ if (!sessionData) {
|
|
|
+ throw new Error('No session data found');
|
|
|
+ }
|
|
|
|
|
|
- if (!response.ok) {
|
|
|
- throw new Error('Failed to fetch stores');
|
|
|
+ const session = JSON.parse(sessionData);
|
|
|
+ const response = await fetch(`${API_URL}/api/stores`, {
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${session.access_token}`,
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
}
|
|
|
+ });
|
|
|
|
|
|
- const data = await response.json();
|
|
|
- if (data.success) {
|
|
|
- setConnectedShops(data.stores || []);
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('Error fetching stores:', error);
|
|
|
- } finally {
|
|
|
- setLoading(false);
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error('Failed to fetch stores');
|
|
|
+ }
|
|
|
+
|
|
|
+ const data = await response.json();
|
|
|
+ if (data.success) {
|
|
|
+ setConnectedShops(data.stores || []);
|
|
|
}
|
|
|
- };
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error fetching stores:', error);
|
|
|
+ } finally {
|
|
|
+ setLoading(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Handle OAuth callbacks
|
|
|
+ useEffect(() => {
|
|
|
+ const params = new URLSearchParams(window.location.search);
|
|
|
+
|
|
|
+ // Handle WooCommerce OAuth callback
|
|
|
+ if (params.get('wc_connected') === 'true') {
|
|
|
+ const storeName = params.get('store');
|
|
|
+ toast({
|
|
|
+ title: "WooCommerce Connected!",
|
|
|
+ description: storeName
|
|
|
+ ? `Successfully connected ${decodeURIComponent(storeName)}`
|
|
|
+ : "Your WooCommerce store has been connected successfully.",
|
|
|
+ });
|
|
|
+ // Clean up URL
|
|
|
+ window.history.replaceState({}, '', '/webshops');
|
|
|
+ // Refresh stores list
|
|
|
+ fetchStores();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Handle errors
|
|
|
+ const error = params.get('error');
|
|
|
+ if (error) {
|
|
|
+ const errorMessages: Record<string, string> = {
|
|
|
+ 'woocommerce_oauth_rejected': 'WooCommerce connection was cancelled. Please try again.',
|
|
|
+ 'woocommerce_oauth_failed': 'Failed to connect to WooCommerce. Please try again.',
|
|
|
+ 'woocommerce_connection_failed': 'Could not connect to your WooCommerce store. Please check your store URL and try again.',
|
|
|
+ 'invalid_store_url': 'Invalid store URL. Please check the URL and try again.',
|
|
|
+ 'failed_to_save': 'Failed to save store connection. Please try again.',
|
|
|
+ 'internal_error': 'An internal error occurred. Please try again later.',
|
|
|
+ };
|
|
|
+
|
|
|
+ toast({
|
|
|
+ title: "Connection Failed",
|
|
|
+ description: errorMessages[error] || "An unexpected error occurred. Please try again.",
|
|
|
+ variant: "destructive",
|
|
|
+ });
|
|
|
+ // Clean up URL
|
|
|
+ window.history.replaceState({}, '', '/webshops');
|
|
|
+ }
|
|
|
+ }, [toast]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
fetchStores();
|
|
|
}, []);
|
|
|
|
|
|
@@ -93,6 +144,47 @@ export function IntegrationsContent() {
|
|
|
setSelectedPlatform(null);
|
|
|
};
|
|
|
|
|
|
+ const handleDisconnectStore = async (storeId: string, storeName: string) => {
|
|
|
+ if (!confirm(`Are you sure you want to disconnect ${storeName}? This action cannot be undone.`)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const sessionData = localStorage.getItem('session_data');
|
|
|
+ if (!sessionData) {
|
|
|
+ throw new Error('No session data found');
|
|
|
+ }
|
|
|
+
|
|
|
+ const session = JSON.parse(sessionData);
|
|
|
+ const response = await fetch(`${API_URL}/api/stores/${storeId}`, {
|
|
|
+ method: 'DELETE',
|
|
|
+ headers: {
|
|
|
+ 'Authorization': `Bearer ${session.access_token}`,
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error('Failed to disconnect store');
|
|
|
+ }
|
|
|
+
|
|
|
+ toast({
|
|
|
+ title: "Store Disconnected",
|
|
|
+ description: `${storeName} has been disconnected successfully.`,
|
|
|
+ });
|
|
|
+
|
|
|
+ // Refresh stores list
|
|
|
+ fetchStores();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error disconnecting store:', error);
|
|
|
+ toast({
|
|
|
+ title: "Disconnection Failed",
|
|
|
+ description: "Failed to disconnect the store. Please try again.",
|
|
|
+ variant: "destructive",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<div className="flex-1 space-y-6 p-8 bg-slate-900">
|
|
|
<div className="flex items-center justify-between">
|
|
|
@@ -146,6 +238,8 @@ export function IntegrationsContent() {
|
|
|
</>
|
|
|
) : selectedPlatform === "shoprenter" ? (
|
|
|
<ShopRenterConnect onClose={handleCloseDialog} />
|
|
|
+ ) : selectedPlatform === "woocommerce" ? (
|
|
|
+ <WooCommerceConnect onClose={handleCloseDialog} />
|
|
|
) : (
|
|
|
<div className="text-center py-8">
|
|
|
<p className="text-white">
|
|
|
@@ -270,8 +364,18 @@ export function IntegrationsContent() {
|
|
|
<tr key={shop.id} className="border-b border-slate-700/50 hover:bg-slate-700/30">
|
|
|
<td className="p-4">
|
|
|
<div>
|
|
|
- <div className="text-white font-medium">{shop.store_name || 'Unnamed Store'}</div>
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <div className="text-white font-medium">{shop.store_name || 'Unnamed Store'}</div>
|
|
|
+ {shop.platform_name === 'woocommerce' && shop.alt_data?.wcVersion && (
|
|
|
+ <Badge variant="outline" className="text-xs border-purple-500 text-purple-400">
|
|
|
+ WC {shop.alt_data.wcVersion}
|
|
|
+ </Badge>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
<div className="text-slate-500 text-xs">{shop.store_url || '-'}</div>
|
|
|
+ {shop.platform_name === 'woocommerce' && shop.alt_data?.wpVersion && (
|
|
|
+ <div className="text-slate-600 text-xs mt-1">WordPress {shop.alt_data.wpVersion}</div>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</td>
|
|
|
<td className="p-4">
|
|
|
@@ -292,7 +396,11 @@ export function IntegrationsContent() {
|
|
|
</div>
|
|
|
</td>
|
|
|
<td className="p-4">
|
|
|
- <Badge className="bg-blue-500 text-white capitalize">
|
|
|
+ <Badge className={`capitalize ${
|
|
|
+ shop.platform_name === 'woocommerce' ? 'bg-purple-500' :
|
|
|
+ shop.platform_name === 'shoprenter' ? 'bg-blue-500' :
|
|
|
+ 'bg-green-500'
|
|
|
+ } text-white`}>
|
|
|
{shop.platform_name}
|
|
|
</Badge>
|
|
|
</td>
|
|
|
@@ -325,8 +433,13 @@ export function IntegrationsContent() {
|
|
|
<PhoneCall className="w-4 h-4 mr-1" />
|
|
|
Phone
|
|
|
</Button>
|
|
|
- <Button variant="ghost" size="sm" className="text-slate-400 hover:text-white">
|
|
|
- <Settings className="w-4 h-4" />
|
|
|
+ <Button
|
|
|
+ size="sm"
|
|
|
+ variant="ghost"
|
|
|
+ className="text-red-400 hover:text-red-300 hover:bg-red-500/10"
|
|
|
+ onClick={() => handleDisconnectStore(shop.id, shop.store_name || 'this store')}
|
|
|
+ >
|
|
|
+ <Trash2 className="w-4 h-4" />
|
|
|
</Button>
|
|
|
</div>
|
|
|
</td>
|