feat: Implement dark mode support across the application
- Added ThemeContext to manage theme state and toggle functionality. - Updated components to support dark mode styles, including header, dashboard, and home page. - Enhanced CSS for smooth transitions between light and dark themes. - Modified authentication context to handle async login operations. - Improved user experience by preserving theme preference in local storage. - Refactored login and register pages to handle OAuth tokens and errors more gracefully.
This commit is contained in:
@@ -45,8 +45,10 @@ GITHUB_CLIENT_SECRET=623db1b4285637d328689857f3fc8ae19d84b7f1
|
||||
|
||||
YANDEX_CLIENT_ID=d8a889ea467f4d699d1854ac7a4f9b48
|
||||
YANDEX_CLIENT_SECRET=e599f43f50274344b3bd9a007692c36b
|
||||
VK_CLIENT_ID=your_vk_client_id_here
|
||||
|
||||
VK_CLIENT_ID=54255963
|
||||
VK_CLIENT_SECRET=your_vk_client_secret_here
|
||||
|
||||
# OAuth Callback URL
|
||||
OAUTH_CALLBACK_URL=https://api.ospab.host/api/auth
|
||||
|
||||
|
||||
@@ -51,17 +51,4 @@ router.get(
|
||||
}
|
||||
);
|
||||
|
||||
// VKontakte OAuth
|
||||
router.get('/vkontakte', passport.authenticate('vkontakte', { scope: ['email'] }));
|
||||
|
||||
router.get(
|
||||
'/vkontakte/callback',
|
||||
passport.authenticate('vkontakte', { session: false, failureRedirect: `${FRONTEND_URL}/login?error=auth_failed` }),
|
||||
(req: Request, res: Response) => {
|
||||
const user = req.user as AuthenticatedUser;
|
||||
const token = jwt.sign({ id: user.id }, JWT_SECRET, { expiresIn: '24h' });
|
||||
res.redirect(`${FRONTEND_URL}/login?token=${token}`);
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -5,7 +5,6 @@ import passport from 'passport';
|
||||
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
|
||||
import { Strategy as GitHubStrategy } from 'passport-github';
|
||||
import { Strategy as YandexStrategy } from 'passport-yandex';
|
||||
import { Strategy as VKontakteStrategy } from 'passport-vkontakte';
|
||||
import { prisma } from '../../prisma/client';
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your_super_secret_key';
|
||||
const OAUTH_CALLBACK_URL = process.env.OAUTH_CALLBACK_URL || 'https://api.ospab.host/api/auth';
|
||||
@@ -123,43 +122,6 @@ if (process.env.YANDEX_CLIENT_ID && process.env.YANDEX_CLIENT_SECRET) {
|
||||
);
|
||||
}
|
||||
|
||||
// VKontakte OAuth
|
||||
if (process.env.VK_CLIENT_ID && process.env.VK_CLIENT_SECRET) {
|
||||
passport.use(
|
||||
new VKontakteStrategy(
|
||||
{
|
||||
clientID: process.env.VK_CLIENT_ID,
|
||||
clientSecret: process.env.VK_CLIENT_SECRET,
|
||||
callbackURL: `${OAUTH_CALLBACK_URL}/vkontakte/callback`,
|
||||
profileFields: ['email', 'city', 'bdate']
|
||||
},
|
||||
async (accessToken: string, refreshToken: string, params: any, profile: any, done: any) => {
|
||||
try {
|
||||
// VK возвращает email в params, а не в profile
|
||||
const email = params.email || profile.emails?.[0]?.value;
|
||||
|
||||
if (!email) {
|
||||
throw new Error('Email не предоставлен ВКонтакте. Убедитесь, что вы разрешили доступ к email.');
|
||||
}
|
||||
|
||||
const oauthProfile: OAuthProfile = {
|
||||
id: profile.id,
|
||||
displayName: profile.displayName || `${profile.name?.givenName || ''} ${profile.name?.familyName || ''}`.trim(),
|
||||
emails: [{ value: email }],
|
||||
provider: 'vkontakte'
|
||||
};
|
||||
|
||||
const user = await findOrCreateUser(oauthProfile);
|
||||
return done(null, user);
|
||||
} catch (error) {
|
||||
return done(error as Error);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
passport.serializeUser((user: any, done) => {
|
||||
done(null, user.id);
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ export const uploadImage = async (req: Request, res: Response) => {
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
data: {
|
||||
url: `https://ospab.host:5000${imageUrl}`,
|
||||
url: `https://api.ospab.host${imageUrl}`,
|
||||
filename: req.file.filename
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user