Skip to content

Commit 3bec9da

Browse files
committed
feat: update user code theme from question single page
1 parent 7f56915 commit 3bec9da

File tree

13 files changed

+122
-60
lines changed

13 files changed

+122
-60
lines changed

src/actions/user/authed/update-user.ts

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,51 @@
22

33
import { prisma } from '@/lib/prisma';
44
import { revalidateTag } from 'next/cache';
5-
import { getUserFromSession } from './get-user';
5+
import { getUser } from './get-user';
66
import { UpdatableUserFields } from '@/types/User';
77

88
export const updateUser = async (opts: {
99
userDetails: Partial<UpdatableUserFields>;
1010
}) => {
11-
try {
12-
const { userDetails } = opts;
13-
14-
console.log('Received update request');
15-
console.log('Raw userDetails:', JSON.stringify(userDetails, null, 2));
16-
17-
if (!userDetails) {
18-
throw new Error('User data is required');
19-
}
20-
21-
// Get the user details from the session
22-
const sessionResult = await getUserFromSession();
23-
24-
// Ensure we have a valid user ID
25-
if (!sessionResult?.data?.user?.id) {
26-
throw new Error('No user found in session');
27-
}
28-
29-
// Clean up the userDetails to remove any undefined or null values
30-
const cleanedUserDetails = Object.fromEntries(
31-
Object.entries(userDetails).filter(
32-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
33-
([_, v]) => v !== undefined && v !== null
34-
)
35-
);
36-
37-
// Update the user in the database
38-
const updatedUser = await prisma.users.update({
39-
where: {
40-
uid: sessionResult.data.user.id,
41-
},
42-
data: cleanedUserDetails,
43-
});
44-
45-
// Revalidate the user details cache
46-
revalidateTag('user-details');
47-
48-
return updatedUser;
49-
} catch (error) {
50-
console.error('Error in updateUser:', error);
51-
throw error;
11+
console.log('updateUser', opts);
12+
13+
const { userDetails } = opts;
14+
15+
if (!userDetails) {
16+
throw new Error('User data is required');
17+
}
18+
19+
// Get the user details from the session
20+
const user = await getUser();
21+
22+
// Ensure we have a valid user ID
23+
if (!user?.uid) {
24+
throw new Error('No user found in session');
5225
}
26+
27+
// Clean up the userDetails to remove any undefined or null values
28+
const cleanedUserDetails = Object.fromEntries(
29+
Object.entries(userDetails).filter(
30+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
31+
([_, v]) => v !== undefined && v !== null
32+
)
33+
);
34+
35+
// Ensure codeEditorTheme is included if provided
36+
if (userDetails.codeEditorTheme !== undefined) {
37+
cleanedUserDetails.codeEditorTheme = userDetails.codeEditorTheme;
38+
}
39+
40+
// Update the user in the database
41+
const updatedUser = await prisma.users.update({
42+
where: {
43+
uid: user.uid,
44+
},
45+
data: cleanedUserDetails,
46+
});
47+
48+
// Revalidate the user details cache
49+
revalidateTag('user-details');
50+
51+
return updatedUser;
5352
};

src/app/(app)/(questions)/question/[slug]/page.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { getQuestion } from '@/utils/data/questions/get';
22
import { Separator } from '@/components/ui/separator';
33
import NoDailyQuestion from '@/components/global/no-daily-question';
4-
import QuestionDisplay from '@/components/app/questions/single/code-snippet';
4+
import CodeDisplay from '@/components/app/questions/single/code-snippet';
55
import { getQuestionStats } from '@/utils/data/questions/get-question-stats';
66
import { useUserServer } from '@/hooks/use-user-server';
77
import QuestionCard from '@/components/app/questions/single/question-card';
88
import { getRandomQuestion } from '@/utils/data/questions/get-random';
9-
import ExpandedCodeModal from '@/components/app/questions/expanded-code-modal';
9+
import ExpandedCodeModal from '@/components/app/questions/single/layout/expanded-code-modal';
1010
import ResizableLayout from '@/components/ui/resizable-layout';
11-
import EditorIcon from '@/components/ui/icons/editor';
12-
import AiQuestionHelp from '@/components/app/questions/ai-question-help';
11+
import AiQuestionHelp from '@/components/app/questions/single/layout/ai-question-help';
12+
import ChangeCodeTheme from '@/components/app/questions/single/layout/change-code-theme';
1313

1414
export default async function TodaysQuestionPage({
1515
params,
@@ -55,17 +55,18 @@ export default async function TodaysQuestionPage({
5555
{/** explain question ai button */}
5656
<AiQuestionHelp question={question} user={user} />
5757
{/** code theme selector */}
58-
<EditorIcon />
58+
<ChangeCodeTheme user={user} />
5959
{/** code snippet */}
6060
{question.codeSnippet && (
6161
<ExpandedCodeModal code={question.codeSnippet} />
6262
)}
6363
</div>
6464
<Separator className="bg-black-50" />
6565
{question?.codeSnippet && (
66-
<QuestionDisplay
66+
<CodeDisplay
6767
content={question.codeSnippet}
6868
backgroundColor="#111111"
69+
user={user}
6970
/>
7071
)}
7172
</div>

src/app/(app)/(questions)/question/custom/[uid]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { getQuestionStats } from '@/utils/data/questions/get-question-stats';
77
import { useUserServer } from '@/hooks/use-user-server';
88
import QuestionCard from '@/components/app/questions/single/question-card';
99
import { getRandomQuestion } from '@/utils/data/questions/get-random';
10-
import ExpandedCodeModal from '@/components/app/questions/expanded-code-modal';
10+
import ExpandedCodeModal from '@/components/app/questions/single/layout/expanded-code-modal';
1111
import RelatedQuestions from '@/components/app/questions/single/related-question-card';
1212
import ResizableLayout from '@/components/ui/resizable-layout';
1313

src/app/(app)/(roadmap)/roadmap/[roadmapUid]/[uid]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { fetchRoadmapQuestion } from '@/utils/data/roadmap/questions/fetch-roadm
1616
import { Button } from '@/components/ui/button';
1717
import { Separator } from '@/components/ui/separator';
1818
import QuestionDisplay from '@/components/app/questions/single/code-snippet';
19-
import ExpandedCodeModal from '@/components/app/questions/expanded-code-modal';
19+
import ExpandedCodeModal from '@/components/app/questions/single/layout/expanded-code-modal';
2020

2121
import { useUserServer } from '@/hooks/use-user-server';
2222
// types

src/app/(app)/(roadmap)/roadmap/[roadmapUid]/onboarding/[index]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import OnboardingQuestionCard from '@/components/app/roadmaps/onboarding/onboard
77
import { redirect } from 'next/navigation';
88
import { checkIfUserIsOnCorrectQuestionIndex } from '@/utils/data/roadmap/questions/check-user-is-on-correct-index';
99
import LoadingSpinner from '@/components/ui/loading';
10-
import ExpandedCodeModal from '@/components/app/questions/expanded-code-modal';
10+
import ExpandedCodeModal from '@/components/app/questions/single/layout/expanded-code-modal';
1111

1212
export default async function RoadmapQuestionPage({
1313
params,

src/app/(marketing)/daily-challenge/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getTotalSubmissions } from '@/actions/demo/get-total-submissions';
22
import { getTodaysQuestion } from '@/utils/data/questions/get-today';
33
import QuestionCard from '@/components/marketing/question/question-card';
4-
import ExpandedCodeModal from '@/components/app/questions/expanded-code-modal';
4+
import ExpandedCodeModal from '@/components/app/questions/single/layout/expanded-code-modal';
55
import { Separator } from '@/components/ui/separator';
66
import { ChartColumn, User } from 'lucide-react';
77
import QuestionDisplay from '@/components/app/questions/single/code-snippet';

src/app/(no_nav)/(auth)/login/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import LoginForm from '@/components/auth/login';
2-
import { Suspense } from 'react';
2+
33
import { createMetadata } from '@/utils/seo';
44

55
export async function generateMetadata() {

src/components/app/questions/resources/question-stats-tab.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Separator } from '@/components/ui/separator';
21
import { Check, User } from 'lucide-react';
32

43
export default function QuestionStatsTab(opts: {

src/components/app/questions/single/answer-question-form.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import { answerQuestionSchema } from '@/lib/zod/schemas/answer-question-schema';
2424
import type { Question } from '@/types/Questions';
2525
import type { UserRecord } from '@/types/User';
2626
import type { Answer } from '@/types/Answers';
27-
import { Separator } from '@/components/ui/separator';
2827

2928
type SchemaProps = z.infer<typeof answerQuestionSchema>;
3029
type AnswerQuestionFormProps = {

src/components/app/questions/single/code-snippet.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
'use client';
22
import React from 'react';
33
import { Highlight, themes } from 'prism-react-renderer';
4-
import { useUser } from '@/hooks/use-user';
4+
import { UserRecord } from '@/types/User';
55

66
interface CodeDisplayProps {
77
content: string;
88
language?: string;
99
backgroundColor?: string;
1010
hideIndex?: boolean;
11+
user?: UserRecord | null;
1112
}
1213

1314
interface HighlightProps {
@@ -29,6 +30,7 @@ export default function CodeDisplay({
2930
language,
3031
backgroundColor = '#111111',
3132
hideIndex = false,
33+
user,
3234
}: CodeDisplayProps) {
3335
// Clean the content by removing pre and code tags
3436
const cleanContent = content
@@ -39,13 +41,13 @@ export default function CodeDisplay({
3941
.replace(/&gt;/g, '>')
4042
.trim();
4143

42-
const { user } = useUser();
43-
4444
return (
4545
<Highlight
46-
theme={themes[(user?.codeEditorTheme as keyof typeof themes) || 'vsDark']}
46+
theme={
47+
themes[user?.codeEditorTheme as keyof typeof themes] || themes.vsDark
48+
}
4749
code={cleanContent}
48-
language={language || 'js'}
50+
language={language || 'javascript'}
4951
>
5052
{({ style, tokens, getLineProps, getTokenProps }: HighlightProps) => (
5153
<pre
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use client';
2+
3+
import EditorIcon from '@/components/ui/icons/editor';
4+
import {
5+
Popover,
6+
PopoverContent,
7+
PopoverTrigger,
8+
} from '@/components/ui/popover';
9+
import {
10+
Select,
11+
SelectItem,
12+
SelectTrigger,
13+
SelectContent,
14+
} from '@/components/ui/select';
15+
import { UserRecord } from '@/types/User';
16+
17+
import { useState } from 'react';
18+
import { themes } from 'prism-react-renderer';
19+
import { useEffect } from 'react';
20+
import { updateUser } from '@/actions/user/authed/update-user';
21+
22+
export default function ChangeCodeTheme({ user }: { user: UserRecord | null }) {
23+
const [selectedTheme, setSelectedTheme] = useState<keyof typeof themes>(
24+
'vs-dark' as keyof typeof themes
25+
);
26+
27+
useEffect(() => {
28+
setSelectedTheme(user?.codeEditorTheme as keyof typeof themes);
29+
}, [user]);
30+
31+
const handleThemeChange = async (theme: keyof typeof themes) => {
32+
console.log('theme', theme);
33+
setSelectedTheme(theme);
34+
await updateUser({ userDetails: { codeEditorTheme: theme } });
35+
};
36+
37+
return (
38+
<Popover>
39+
<PopoverTrigger>
40+
<EditorIcon />
41+
</PopoverTrigger>
42+
<PopoverContent
43+
className="bg-black-100 text-white border border-black-50 flex flex-col gap-y-2"
44+
align="end"
45+
>
46+
<h5 className="text-lg font-semibold mb-2">Code Theme</h5>
47+
<Select onValueChange={handleThemeChange} value={selectedTheme}>
48+
<SelectTrigger className="border border-black-50 w-full">
49+
{selectedTheme}
50+
</SelectTrigger>
51+
<SelectContent>
52+
{Object.entries(themes).map(([key]) => (
53+
<SelectItem key={key} value={key}>
54+
{key}
55+
</SelectItem>
56+
))}
57+
</SelectContent>
58+
</Select>
59+
</PopoverContent>
60+
</Popover>
61+
);
62+
}

0 commit comments

Comments
 (0)