ALwrity + Wix + Wordpress + GSC integration + Production API calls fixes

This commit is contained in:
ajaysi
2025-10-09 13:07:09 +05:30
parent 0f6f8a4c6c
commit 9cc1ffd47e
20 changed files with 350 additions and 846 deletions

View File

@@ -6,6 +6,7 @@ import {
Fade,
Container,
Grid,
Snackbar,
} from '@mui/material';
import { Lock } from '@mui/icons-material';
import OnboardingButton from './common/OnboardingButton';
@@ -23,7 +24,6 @@ interface ApiKeyStepProps {
}
const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent }) => {
const [currentProvider, setCurrentProvider] = useState(0);
const [focusedProvider, setFocusedProvider] = useState<any>(null);
const {
@@ -36,6 +36,10 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
selectedProvider,
providers,
isValid,
currentProviderIndex,
setCurrentProviderIndex,
showCompletionToast,
setShowCompletionToast,
setShowHelp,
handleContinue,
handleBenefitsClick,
@@ -55,13 +59,14 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
// Set initial focused provider
if (providers.length > 0) {
setFocusedProvider(providers[currentProvider] ?? providers[0]);
setFocusedProvider(providers[currentProviderIndex] ?? providers[0]);
}
}, [updateHeaderContent, providers, currentProvider]);
}, [updateHeaderContent, providers, currentProviderIndex]);
return (
<Fade in={true} timeout={500}>
<Container maxWidth="lg" sx={{ py: 2 }}>
<>
<Fade in={true} timeout={500}>
<Container maxWidth="lg" sx={{ py: 2 }}>
<form onSubmit={(e) => { e.preventDefault(); handleContinue(); }}>
{/* Main Content Layout */}
<Grid container spacing={4} sx={{ mb: 4 }}>
@@ -69,8 +74,8 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
<Grid item xs={12} lg={8}>
<ApiKeyCarousel
providers={providers}
currentProvider={currentProvider}
setCurrentProvider={setCurrentProvider}
currentProvider={currentProviderIndex}
setCurrentProvider={setCurrentProviderIndex}
onProviderFocus={handleProviderFocus}
/>
</Grid>
@@ -80,7 +85,7 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
<ApiKeySidebar
currentProvider={focusedProvider}
allProviders={providers}
currentStep={currentProvider + 1}
currentStep={currentProviderIndex + 1}
totalSteps={providers.length}
/>
</Grid>
@@ -169,7 +174,7 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
}
}}
>
{isValid ? 'Continue to Website Analysis' : 'Complete All Required API Keys'}
{isValid ? 'Continue' : 'Complete All Required API Keys'}
</OnboardingButton>
</Box>
@@ -197,8 +202,42 @@ const ApiKeyStep: React.FC<ApiKeyStepProps> = ({ onContinue, updateHeaderContent
</Typography>
</Box>
</form>
</Container>
</Fade>
</Container>
</Fade>
{/* Completion Toast */}
<Snackbar
open={showCompletionToast}
autoHideDuration={5000}
onClose={() => setShowCompletionToast(false)}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
sx={{
'& .MuiSnackbarContent-root': {
background: 'linear-gradient(135deg, #10B981 0%, #059669 100%)',
color: 'white',
fontWeight: 600,
fontSize: '1rem',
borderRadius: '12px',
boxShadow: '0 8px 32px rgba(16, 185, 129, 0.3)',
},
}}
>
<Alert
onClose={() => setShowCompletionToast(false)}
severity="success"
sx={{
width: '100%',
background: 'transparent',
color: 'white',
'& .MuiAlert-icon': {
color: 'white',
},
}}
>
🎉 All API keys configured! Click Continue to proceed to Website Analysis.
</Alert>
</Snackbar>
</>
);
};

View File

@@ -3,6 +3,7 @@ import { useAuth } from '@clerk/clerk-react';
import { getApiKeysForOnboarding, getStep1ApiKeysFromProgress, saveApiKey } from '../../../../api/onboarding';
import { getKeyStatus, formatErrorMessage } from '../../common/onboardingUtils';
import { Provider } from './ProviderCard';
import { apiClient } from '../../../../api/client';
export const useApiKeyStep = (onContinue: (stepData?: any) => void) => {
const { getToken } = useAuth();
@@ -20,6 +21,8 @@ export const useApiKeyStep = (onContinue: (stepData?: any) => void) => {
const [benefitsModalOpen, setBenefitsModalOpen] = useState(false);
const [selectedProvider, setSelectedProvider] = useState<Provider | null>(null);
const [keysLoaded, setKeysLoaded] = useState(false);
const [currentProviderIndex, setCurrentProviderIndex] = useState(0);
const [showCompletionToast, setShowCompletionToast] = useState(false);
const loadExistingKeys = useCallback(async () => {
try {
@@ -131,34 +134,22 @@ export const useApiKeyStep = (onContinue: (stepData?: any) => void) => {
// Complete step 1 with the API keys data
console.log('ApiKeyStep: Attempting to complete step 1 with data:', stepData);
let response;
try {
response = await fetch('/api/onboarding/step/1/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${await getToken()}`
},
body: JSON.stringify({ data: stepData })
});
console.log('ApiKeyStep: Step completion response status:', response.status);
const response = await apiClient.post('/api/onboarding/step/1/complete', { data: stepData });
console.log('ApiKeyStep: Step completion response:', response.data);
} catch (fetchError: any) {
console.error('Network error completing step:', fetchError);
setError('Network error. Please check your connection and try again.');
setLoading(false);
return;
}
if (!response.ok) {
let errorMessage = 'Failed to complete step';
try {
const errorData = await response.json();
console.log('ApiKeyStep: Error response data:', errorData);
errorMessage = errorData.detail || errorMessage;
} catch (parseError) {
console.error('Error parsing error response:', parseError);
errorMessage = `Server error (${response.status}). Please try again.`;
console.error('Error completing step:', fetchError);
let errorMessage = 'Failed to complete step. Please try again.';
if (fetchError.response) {
// Server responded with an error
console.log('ApiKeyStep: Error response data:', fetchError.response.data);
errorMessage = fetchError.response.data?.detail || errorMessage;
} else if (fetchError.request) {
// Request made but no response
errorMessage = 'Network error. Please check your connection and try again.';
}
console.log('ApiKeyStep: Setting error message:', errorMessage);
setError(errorMessage);
setLoading(false);
@@ -228,6 +219,31 @@ export const useApiKeyStep = (onContinue: (stepData?: any) => void) => {
// All three keys are required
const isValid = geminiKey.trim() && exaKey.trim() && copilotkitKey.trim();
// Auto-scroll to next provider when current one is valid
useEffect(() => {
if (currentProviderIndex < 2) {
const currentKey = currentProviderIndex === 0 ? geminiKey :
currentProviderIndex === 1 ? exaKey : copilotkitKey;
if (currentKey.trim() && getKeyStatus(currentKey, currentProviderIndex === 0 ? 'gemini' :
currentProviderIndex === 1 ? 'exa' : 'copilotkit') === 'valid') {
// Auto-scroll to next provider after a short delay
setTimeout(() => {
setCurrentProviderIndex(prev => prev + 1);
}, 1000);
}
}
}, [geminiKey, exaKey, copilotkitKey, currentProviderIndex]);
// Show completion toast when all keys are valid
useEffect(() => {
if (isValid && keysLoaded) {
setShowCompletionToast(true);
// Auto-hide toast after 5 seconds
setTimeout(() => setShowCompletionToast(false), 5000);
}
}, [isValid, keysLoaded]);
const handleBenefitsClick = (provider: Provider) => {
setSelectedProvider(provider);
setBenefitsModalOpen(true);
@@ -260,6 +276,10 @@ export const useApiKeyStep = (onContinue: (stepData?: any) => void) => {
keysLoaded,
providers,
isValid,
currentProviderIndex,
setCurrentProviderIndex,
showCompletionToast,
setShowCompletionToast,
// Actions
setShowHelp,

View File

@@ -17,6 +17,7 @@ import {
IconButton,
Tooltip
} from '@mui/material';
import { apiClient } from '../../api/client';
import {
ExpandMore as ExpandMoreIcon,
ContentCopy as CopyIcon,
@@ -93,21 +94,13 @@ const StyleDetectionStep: React.FC<StyleDetectionStepProps> = ({ onContinue }) =
include_guidelines: true
};
const response = await fetch('/api/onboarding/style-detection/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
});
const response = await apiClient.post('/api/onboarding/style-detection/complete', requestData);
const result = await response.json();
if (result.success) {
setAnalysis(result.style_analysis);
if (response.data.success) {
setAnalysis(response.data.style_analysis);
setSuccess('Style analysis completed successfully!');
} else {
setError(result.error || 'Analysis failed');
setError(response.data.error || 'Analysis failed');
}
} catch (err) {
setError('Failed to analyze content. Please try again.');

View File

@@ -63,8 +63,13 @@ export const usePlatformConnections = () => {
const redirectUri = `${redirectOrigin}/wix/callback`;
const oauthData = await wixClient.auth.generateOAuthData(redirectUri);
// Use sessionStorage to ensure data is scoped to this tab/session (like WixTestPage)
sessionStorage.setItem('wix_oauth_data', JSON.stringify(oauthData));
// Persist OAuth data robustly so callback can always recover it
// 1) SessionStorage for same-origin same-tab flows
try { sessionStorage.setItem('wix_oauth_data', JSON.stringify(oauthData)); } catch {}
// 2) Key by state so callback can look up by state value
try { sessionStorage.setItem(`wix_oauth_data_${oauthData.state}`, JSON.stringify(oauthData)); } catch {}
// 3) window.name persists across top-level redirects even when origin changes
try { (window as any).name = `WIX_OAUTH::${btoa(JSON.stringify(oauthData))}`; } catch {}
const { authUrl } = await wixClient.auth.getAuthUrl(oauthData);
window.location.href = authUrl;
} catch (error) {