Skip to content

Commit 283c77d

Browse files
committed
refactor(code): split code into smaller modules
1 parent 5a89805 commit 283c77d

12 files changed

+315
-309
lines changed

.env.example

-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
# you can get your gemini api key from https://aistudio.google.com/app/apikey
22
API_KEY=your_gemini_api_key_here
3-
4-
VERCEL_URL="localhost:3000"

action/index.ts

+21-50
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,51 @@
11
"use server";
22

3-
import { model } from "@/utils";
3+
import { handleModelResponse } from "@/utils";
4+
import { generateSystemInstruction } from "@/utils/instructions";
45

5-
export const commitChange = async ({
6-
message,
7-
isEmojiSupport,
8-
}: {
6+
type ActionProps = {
97
message: string | null;
108
isEmojiSupport: boolean;
11-
}): Promise<{
9+
};
10+
11+
type ActionPromise = {
1212
data: {
1313
text: string;
1414
} | null;
1515
error: string | null;
16-
}> => {
16+
};
17+
18+
export const commitChange = async ({
19+
message,
20+
isEmojiSupport,
21+
}: ActionProps): Promise<ActionPromise> => {
1722
if (!message || message.trim() === "") {
1823
return { data: null, error: "Please enter a message" };
1924
}
2025

2126
try {
22-
const modelResponse = model.generateContent({
23-
contents: [{ role: "user", parts: [{ text: message }] }],
24-
systemInstruction: `\
25-
You are an assistant that helps to provide Git commit messages based on https://www.conventionalcommits.org/en/v1.0.0/.
26-
27-
- Provide a Git commit message in a code block as txt.
28-
- Do not include the full command (e.g., \`git commit -m "here git message"\`).
29-
- Only provide the commit message itself.
30-
- Suggest 3 different commit messages to give the user some options.
31-
- For example, if the user input is "I change lib folder to utils folder", then the output should be:
32-
33-
${
34-
isEmojiSupport &&
35-
`\
36-
- Use emojis in the commit message.
37-
- For emojis, you can use https://gitmoji.dev/
38-
- Don't provide a description, just the commit message.
39-
- For example, if the user input is "I change lib folder to utils folder", then the output should be:
40-
`
41-
}
42-
43-
${
44-
isEmojiSupport
45-
? `
46-
\`\`\`txt \n ♻️ refactor(lib): change lib folder to utils folder \n\`\`\`\n
47-
\`\`\`txt \n ➕ refactor(deps): rename lib folder to utils \n\`\`\`\n
48-
\`\`\`txt \n ✏️ fix(deps): rename lib folder to utils \n\`\`\`\n
49-
`
50-
: `
51-
\`\`\`txt \n refactor(lib): change lib folder to utils folder \n\`\`\`\n
52-
\`\`\`txt \n refactor(deps): rename lib folder to utils \n\`\`\`\n
53-
\`\`\`txt \n fix(deps): rename lib folder to utils \n\`\`\`\n
54-
`
55-
}
56-
57-
`,
58-
});
59-
60-
const response = (await modelResponse).response.text();
27+
const systemInstruction = generateSystemInstruction(isEmojiSupport);
28+
const responseText = await handleModelResponse(systemInstruction, message);
6129

6230
console.log({
6331
message: message,
64-
response: response,
32+
response: responseText,
6533
data: {
6634
time: new Date().toISOString(),
6735
},
6836
});
6937

7038
return {
7139
data: {
72-
text: response,
40+
text: responseText,
7341
},
7442
error: null,
7543
};
76-
} catch (error) {
44+
} catch (error: any) {
7745
console.log("error on action", error);
78-
return { data: null, error: "something went wrong!" };
46+
return {
47+
data: null,
48+
error: error?.statusText ? error.statusText : "something went wrong!",
49+
};
7950
}
8051
};

app/layout.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Metadata } from "next";
2-
import { Inter } from "next/font/google";
32
import "./globals.css";
43
import { ThemeProvider } from "@/components/provider/theme-provider";
54
import { Toaster } from "@/components/ui/toaster";
@@ -13,8 +12,6 @@ import Image from "next/image";
1312
import NotificationBanner from "@/components/notificationBanner";
1413
import { TooltipProvider } from "@/components/ui/tooltip";
1514

16-
const inter = Inter({ subsets: ["latin"] });
17-
1815
export const metadata: Metadata = {
1916
title: {
2017
default: siteConfig.name,
@@ -55,7 +52,7 @@ export default function RootLayout({
5552
}>) {
5653
return (
5754
<html lang="en">
58-
<body className={`${inter.className}`}>
55+
<body>
5956
<ThemeProvider
6057
attribute="class"
6158
defaultTheme="dark"
@@ -93,6 +90,7 @@ export default function RootLayout({
9390
</div>
9491
<Link
9592
href={"https://github.com/ruru-m07/commitly"}
93+
aria-label="Github"
9694
target="_blank"
9795
className={cn(
9896
buttonVariants({

app/page.tsx

+3-190
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,5 @@
1-
"use client";
1+
import Home from "@/components/home";
22

3-
import { commitChange } from "@/action";
4-
import { Button } from "@/components/ui/button";
5-
import { Card } from "@/components/ui/card";
6-
import { Input } from "@/components/ui/input";
7-
import { Label } from "@/components/ui/label";
8-
import { ScrollArea } from "@/components/ui/scroll-area";
9-
import { toastVariants } from "@/components/ui/toast";
10-
import { useToast } from "@/components/ui/use-toast";
11-
import { cn } from "@/lib/utils";
12-
import { CornerDownLeft } from "lucide-react";
13-
import React from "react";
14-
import dynamic from "next/dynamic";
15-
import ListSuggestion from "@/components/listSuggestion";
16-
import Loader from "@/components/loader";
17-
import { Spinner } from "@/components/ui/spinner";
18-
import { Switch } from "@/components/ui/switch";
19-
import {
20-
Tooltip,
21-
TooltipContent,
22-
TooltipTrigger,
23-
} from "@/components/ui/tooltip";
24-
25-
const EmptyScreen = dynamic(() => import("@/components/emptyScreen"), {
26-
ssr: false,
27-
loading: () => <Loader />,
28-
});
29-
30-
export default function Home() {
31-
const [message, setMessage] = React.useState<string | null>(null);
32-
const [isLoading, setIsLoading] = React.useState(false);
33-
const [error, setError] = React.useState<string | null>(null);
34-
const [commitChanges, setcommitChanges] = React.useState<string | null>(null);
35-
const [isEmojiSupport, setIsEmojiSupport] = React.useState<boolean>(false);
36-
const [commitMessages, setcommitMessages] = React.useState<string | null>(
37-
null
38-
);
39-
40-
const { toast } = useToast();
41-
42-
const handelSubmit = async ({
43-
suggestion,
44-
force = false,
45-
}: {
46-
suggestion: string;
47-
force?: boolean;
48-
}) => {
49-
if (!force && suggestion === commitChanges) {
50-
toast({
51-
variant: "destructive",
52-
title: "Duplicate Message",
53-
description: "Please enter a different message.",
54-
});
55-
return;
56-
}
57-
58-
setIsLoading(true);
59-
setError(null);
60-
61-
try {
62-
const { data, error } = await commitChange({
63-
message: suggestion,
64-
isEmojiSupport: isEmojiSupport,
65-
});
66-
67-
if (error) {
68-
setError(error);
69-
toast({
70-
variant: "destructive",
71-
title: "Uh oh! Something went wrong.",
72-
description: error,
73-
action: (
74-
<button
75-
className={cn(
76-
toastVariants({
77-
variant: "destructive",
78-
className: "w-fit m-0 p-2 text-xs hover:bg-[#815305]/35",
79-
})
80-
)}
81-
onClick={() => handelSubmit({ suggestion })}
82-
>
83-
Try again
84-
</button>
85-
),
86-
});
87-
} else {
88-
if (data) {
89-
setcommitMessages(data.text);
90-
console.log(data.text);
91-
setcommitChanges(suggestion);
92-
setMessage("");
93-
}
94-
}
95-
} catch (error) {
96-
console.log(error);
97-
} finally {
98-
setIsLoading(false);
99-
}
100-
};
101-
102-
const submitForm = (
103-
e: React.FormEvent<HTMLFormElement>,
104-
message: string | null
105-
): void => {
106-
e.preventDefault();
107-
handelSubmit({ suggestion: message || "" });
108-
};
109-
110-
return (
111-
<div className=" h-full py-10 flex items-center justify-center">
112-
<ScrollArea className="h-screen w-full">
113-
<div className=" flex h-screen mx-0 lg:mx-48 xl:mx-60 flex-col p-4 lg:col-span-2">
114-
<div className="w-full h-5/6 mb-2 flex items-end">
115-
<Card className="h-full w-full py-4 flex justify-center items-center bg-primary-foreground/25">
116-
<ScrollArea className=" flex justify-center items-center w-full">
117-
{error ? (
118-
<div className="w-full flex items-center justify-center">
119-
<h3 className="scroll-m-20 text-2xl font-semibold tracking-tight">
120-
Oops! Something Went Wrong!{" "}
121-
<span className="ml-2"> : ( </span>
122-
</h3>
123-
<p className="text-sm text-muted-foreground">{error}</p>
124-
</div>
125-
) : isLoading ? (
126-
<div className="w-full flex items-center justify-center">
127-
<Loader />
128-
</div>
129-
) : commitMessages ? (
130-
<ListSuggestion
131-
suggestions={commitMessages!}
132-
commitChanges={commitChanges || ""}
133-
submitForm={submitForm}
134-
forceSubmit={handelSubmit}
135-
/>
136-
) : (
137-
<div className="w-full flex items-center justify-center">
138-
<EmptyScreen onSubmit={handelSubmit} />
139-
</div>
140-
)}
141-
</ScrollArea>
142-
</Card>
143-
</div>
144-
145-
<div className="flex-1" />
146-
147-
<form
148-
onSubmit={(e) => submitForm(e, message)}
149-
className="relative overflow-hidden rounded-lg border bg-primary-foreground/25 focus-within:ring-1 focus-within:ring-ring shadow"
150-
>
151-
<Label htmlFor="message" className="sr-only">
152-
Message
153-
</Label>
154-
<Input
155-
id="message"
156-
placeholder="Describe your changes here..."
157-
className="min-h-12 resize-none border-0 p-3 shadow-none focus-visible:ring-0"
158-
onChange={(e) => setMessage(e.target.value)}
159-
value={message || ""}
160-
disabled={isLoading}
161-
autoComplete="off"
162-
autoFocus
163-
required
164-
/>
165-
<div className="flex items-center p-3 pt-0">
166-
<div className="flex items-center space-x-2">
167-
<Switch
168-
onCheckedChange={(e) => setIsEmojiSupport(e)}
169-
id="emoji-mode"
170-
/>
171-
<Label htmlFor="emoji-mode">Emoji Mode</Label>
172-
</div>
173-
<Button
174-
type="submit"
175-
size="sm"
176-
className={cn("ml-auto gap-1.5", {
177-
"bg-primary-foreground text-muted-foreground border cursor-not-allowed hover:bg-primary-foreground":
178-
!message || isLoading,
179-
})}
180-
disabled={isLoading}
181-
>
182-
{isLoading && <Spinner className="size-4" />}
183-
Generate
184-
<CornerDownLeft className="size-3.5" />
185-
</Button>
186-
</div>
187-
</form>
188-
</div>
189-
</ScrollArea>
190-
</div>
191-
);
3+
export default function Page() {
4+
return <Home />;
1925
}

components/errorComponent.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from "react";
2+
3+
interface ErrorComponentProps {
4+
error: string;
5+
}
6+
7+
const ErrorComponent: React.FC<ErrorComponentProps> = ({ error }) => {
8+
return (
9+
<div className="w-full flex flex-col items-center justify-center">
10+
<h3 className="scroll-m-20 text-2xl font-semibold tracking-tight">
11+
Oops! Something Went Wrong! <span className="ml-2"> : ( </span>
12+
</h3>
13+
<p className="text-sm text-muted-foreground mt-2">{error}</p>
14+
</div>
15+
);
16+
};
17+
18+
export default ErrorComponent;

0 commit comments

Comments
 (0)