working nhost client
هذا الالتزام موجود في:
@@ -23,6 +23,14 @@ function App() {
|
||||
<Route path="/portfolio" element={<ProtectedRoute><Portfolio /></ProtectedRoute>} />
|
||||
<Route path="/strategy" element={<ProtectedRoute><Strategy /></ProtectedRoute>} />
|
||||
<Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
|
||||
|
||||
|
||||
{/* <Route path="/" element={<Dashboard />} />
|
||||
<Route path="/portfolio" element={<Portfolio />} />
|
||||
<Route path="/strategy" element={<Strategy />} />
|
||||
<Route path="/settings" element={<Settings />} /> */}
|
||||
|
||||
|
||||
</Routes>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
103
src/main.tsx
103
src/main.tsx
@@ -1,11 +1,106 @@
|
||||
// بسم الله الرحمن الرحيم
|
||||
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import './App.css'
|
||||
import App from './App.tsx'
|
||||
import { NhostProvider, NhostClient } from '@nhost/react'
|
||||
import { ApolloClient, InMemoryCache, createHttpLink, split } from "@apollo/client"
|
||||
import { ApolloProvider } from "@apollo/client/react";
|
||||
import { setContext } from '@apollo/client/link/context'
|
||||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
|
||||
import { createClient } from 'graphql-ws'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
|
||||
// Initialize Nhost client
|
||||
const nhost = new NhostClient({
|
||||
authUrl: 'https://onekeyword-auth-76aaf2ee939c.hosted.ghaymah.systems',
|
||||
storageUrl: 'https://onekeyword-auth-76aaf2ee939c.hosted.ghaymah.systems',
|
||||
functionsUrl: 'https://onekeyword-auth-76aaf2ee939c.hosted.ghaymah.systems',
|
||||
graphqlUrl: 'https://onekeyword-auth-76aaf2ee939c.hosted.ghaymah.systems',
|
||||
})
|
||||
|
||||
// Auth link for Apollo Client
|
||||
const authLink = setContext(async (_, { headers }) => {
|
||||
// Get the authentication state from Nhost
|
||||
const isAuthenticated = await nhost.auth.isAuthenticatedAsync()
|
||||
|
||||
if (isAuthenticated) {
|
||||
const token = nhost.auth.getAccessToken()
|
||||
return {
|
||||
headers: {
|
||||
...headers,
|
||||
authorization: token ? `Bearer ${token}` : '',
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use public role when not authenticated
|
||||
return {
|
||||
headers: {
|
||||
...headers,
|
||||
'x-hasura-role': 'public',
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// HTTP link for queries and mutations
|
||||
const httpLink = createHttpLink({
|
||||
uri: 'https://hasura-bc7db43160df.hosted.ghaymah.systems/v1/graphql',
|
||||
|
||||
})
|
||||
|
||||
// WebSocket link for subscriptions
|
||||
const wsLink = new GraphQLWsLink(
|
||||
createClient({
|
||||
url: 'wss://hasura-bc7db43160df.hosted.ghaymah.systems/v1/graphql',
|
||||
connectionParams: async () => {
|
||||
const isAuthenticated = await nhost.auth.isAuthenticatedAsync()
|
||||
|
||||
if (isAuthenticated) {
|
||||
const token = nhost.auth.getAccessToken()
|
||||
return {
|
||||
headers: {
|
||||
authorization: token ? `Bearer ${token}` : '',
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
headers: {
|
||||
'x-hasura-role': 'public',
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
// Split links based on operation type
|
||||
const splitLink = split(
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query)
|
||||
return (
|
||||
definition.kind === 'OperationDefinition' &&
|
||||
definition.operation === 'subscription'
|
||||
)
|
||||
},
|
||||
wsLink,
|
||||
authLink.concat(httpLink)
|
||||
)
|
||||
|
||||
// Apollo Client setup
|
||||
const client = new ApolloClient({
|
||||
link: splitLink,
|
||||
cache: new InMemoryCache(),
|
||||
})
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
<NhostProvider nhost={nhost}>
|
||||
<StrictMode>
|
||||
<ApolloProvider client={client}>
|
||||
<App />
|
||||
</ApolloProvider>
|
||||
</StrictMode>
|
||||
</NhostProvider>,
|
||||
)
|
||||
1021
src/pages/login.tsx
1021
src/pages/login.tsx
تم حذف اختلاف الملف لأن الملف كبير جداً
تحميل الاختلاف
213
src/pages/useAuth.tsx
Normal file
213
src/pages/useAuth.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
import { useState } from 'react';
|
||||
import { useNhostClient } from '@nhost/react';
|
||||
|
||||
export const useAuth = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const nhost = useNhostClient();
|
||||
|
||||
const handleLogin = async (email: string, password: string) => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const { session, error } = await nhost.auth.signIn({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message || 'Failed to login. Please check your credentials.');
|
||||
}
|
||||
|
||||
if (session) {
|
||||
const accessToken = session.accessToken;
|
||||
const refreshToken = session.refreshToken;
|
||||
const userId = session.user?.id;
|
||||
|
||||
// Store user data in localStorage
|
||||
const userData = {
|
||||
email,
|
||||
accessToken,
|
||||
userId,
|
||||
isLoggedIn: true,
|
||||
lastLogin: new Date().toISOString()
|
||||
};
|
||||
|
||||
localStorage.setItem('sp_user', JSON.stringify(userData));
|
||||
localStorage.setItem('user_id', userId);
|
||||
window.dispatchEvent(new Event('userChanged'));
|
||||
|
||||
// Store tokens in HttpOnly cookies (if still needed)
|
||||
try {
|
||||
await fetch('/api/auth/store-tokens', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
expires_in: 3600
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error storing token in HttpOnly cookie:', error);
|
||||
}
|
||||
|
||||
return { success: true, data: { session } };
|
||||
} else {
|
||||
throw new Error('Login failed: No session returned');
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSignUp = async (email: string, password: string) => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const { session, error } = await nhost.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message || 'Signup failed. Please check your info.');
|
||||
}
|
||||
|
||||
if (session) {
|
||||
const accessToken = session.accessToken;
|
||||
const refreshToken = session.refreshToken;
|
||||
const userId = session.user?.id;
|
||||
|
||||
const userData = {
|
||||
email,
|
||||
accessToken,
|
||||
userId,
|
||||
isLoggedIn: true,
|
||||
lastLogin: new Date().toISOString()
|
||||
};
|
||||
|
||||
localStorage.setItem('sp_user', JSON.stringify(userData));
|
||||
localStorage.setItem('user_id', userId);
|
||||
window.dispatchEvent(new Event('userChanged'));
|
||||
|
||||
// Store tokens in HttpOnly cookies (if still needed)
|
||||
try {
|
||||
await fetch('/api/auth/store-tokens', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify({
|
||||
access_token: accessToken,
|
||||
refresh_token: refreshToken,
|
||||
expires_in: 3600
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error storing token in HttpOnly cookie:', error);
|
||||
}
|
||||
|
||||
return { success: true, data: { session } };
|
||||
} else {
|
||||
// Note: NHost may not return a session immediately if email verification is required
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
message: 'Signup successful! Please check your email for verification.'
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleForgotPassword = async (email: string) => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const { error } = await nhost.auth.resetPassword({ email });
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message || 'Failed to send reset email.');
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'If the email exists, a reset link has been sent.'
|
||||
};
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Additional NHost auth methods you might find useful
|
||||
const handleSignOut = async () => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const { error } = await nhost.auth.signOut();
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message || 'Failed to sign out.');
|
||||
}
|
||||
|
||||
// Clear local storage
|
||||
localStorage.removeItem('sp_user');
|
||||
localStorage.removeItem('user_id');
|
||||
window.dispatchEvent(new Event('userChanged'));
|
||||
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangePassword = async (newPassword: string) => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const { error } = await nhost.auth.changePassword({ newPassword });
|
||||
|
||||
if (error) {
|
||||
throw new Error(error.message || 'Failed to change password.');
|
||||
}
|
||||
|
||||
return { success: true, message: 'Password changed successfully.' };
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred';
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
handleLogin,
|
||||
handleSignUp,
|
||||
handleForgotPassword,
|
||||
handleSignOut,
|
||||
handleChangePassword,
|
||||
setError
|
||||
};
|
||||
};
|
||||
المرجع في مشكلة جديدة
حظر مستخدم