Skip to content

Commit f46604a

Browse files
authored
feat(app): implement new UI and update action and remove unused API (#9)
* feat(app): implement new UI and update action and remove unused API * chore(package): update version, description, author and repository name
1 parent b41648c commit f46604a

18 files changed

+363
-452
lines changed

action/index.ts

+38-16
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,50 @@
11
"use server";
22

3-
import { model, systemHistory } from "@/utils";
4-
import { Content } from "@google/generative-ai";
3+
import { model } from "@/utils";
54

6-
export const commitMessage = async ({
5+
export const commitChange = async ({
76
message,
8-
history,
97
}: {
10-
message: string;
11-
history: Content[];
12-
}) => {
13-
const chat = model.startChat({
14-
history: [...(await systemHistory()), ...history],
15-
});
8+
message: string | null;
9+
}): Promise<{
10+
data: {
11+
text: string;
12+
} | null;
13+
error: string | null;
14+
}> => {
15+
if (!message || message.trim() === "") {
16+
return { data: null, error: "Please enter a message" };
17+
}
1618

1719
try {
18-
const result = await chat.sendMessage(message);
19-
const response = result.response;
20+
const modelResponse = model.generateContent({
21+
contents: [{ role: "user", parts: [{ text: message }] }],
22+
systemInstruction: `\
23+
You are an assistant that helps to provide Git commit messages based on https://www.conventionalcommits.org/en/v1.0.0/.
24+
25+
- Provide a Git commit message in a code block as txt.
26+
- Do not include the full command (e.g., \`git commit -m "here git message"\`).
27+
- Only provide the commit message itself.
28+
- Suggest 3 different commit messages to give the user some options.
29+
- For example, if the user input is "I change lib folder to utils folder", then the output should be:
30+
31+
\`\`\`txt refactor(lib): change lib folder to utils folder \n\`\`\`\n
32+
\`\`\`txt refactor(deps): rename lib folder to utils \n\`\`\`\n
33+
\`\`\`txt fix(deps): rename lib folder to utils \n\`\`\`\n
34+
35+
`,
36+
});
2037

21-
const text = response.text();
22-
console.log("text", text);
38+
const response = (await modelResponse).response.text();
2339

24-
return { success: true, text: text };
40+
return {
41+
data: {
42+
text: response,
43+
},
44+
error: null,
45+
};
2546
} catch (error) {
26-
return { success: false, error: error as string };
47+
console.log("error on action", error);
48+
return { data: null, error: "something went wrong!" };
2749
}
2850
};

app/api/route.ts

-27
This file was deleted.

app/layout.tsx

+38-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import "./globals.css";
44
import { ThemeProvider } from "@/components/provider/theme-provider";
55
import { Toaster } from "@/components/ui/toaster";
66
import { siteConfig } from "@/config/site";
7+
import Link from "next/link";
8+
import { cn } from "@/lib/utils";
9+
import { buttonVariants } from "@/components/ui/button";
10+
import { GitHubLogoIcon } from "@radix-ui/react-icons";
11+
import { ModeToggle } from "@/components/modeToggle";
12+
import Image from "next/image";
713

814
const inter = Inter({ subsets: ["latin"] });
915

@@ -54,7 +60,38 @@ export default function RootLayout({
5460
enableSystem
5561
disableTransitionOnChange
5662
>
57-
{children}
63+
<main className="mx-10 lg:mx-20">
64+
<section className="h-screen">
65+
<div className="w-full flex justify-end absolute top-0 right-0 items-center mr-10 mt-3 z-10">
66+
<div
67+
className={cn(
68+
buttonVariants({
69+
variant: "outline",
70+
size: "icon",
71+
className: "rounded-full w-10 h-10 overflow-hidden",
72+
})
73+
)}
74+
>
75+
<Image src={'/logo.jpeg'} alt="logo" width={100} height={100} />
76+
</div>
77+
<Link
78+
href={"https://github.com/ruru-m07/commitly"}
79+
target="_blank"
80+
className={cn(
81+
buttonVariants({
82+
variant: "outline",
83+
size: "icon",
84+
className: "rounded-full mx-2 w-10 h-10",
85+
})
86+
)}
87+
>
88+
<GitHubLogoIcon className="w-6 h-6" />
89+
</Link>
90+
<ModeToggle />
91+
</div>
92+
{children}
93+
</section>
94+
</main>
5895
<Toaster />
5996
</ThemeProvider>
6097
</body>

app/page.tsx

+114-75
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,157 @@
11
"use client";
22

3-
import { commitMessage } from "@/action";
4-
import AiLoading from "@/components/AiLoading";
5-
import Navbar from "@/components/Navbar";
6-
import ListChat from "@/components/listChat";
3+
import { commitChange } from "@/action";
74
import { Button } from "@/components/ui/button";
5+
import { Card } from "@/components/ui/card";
86
import { Input } from "@/components/ui/input";
97
import { Label } from "@/components/ui/label";
108
import { ScrollArea } from "@/components/ui/scroll-area";
9+
import { toastVariants } from "@/components/ui/toast";
1110
import { useToast } from "@/components/ui/use-toast";
12-
import { Content } from "@google/generative-ai";
11+
import { cn } from "@/lib/utils";
1312
import { CornerDownLeft } from "lucide-react";
1413
import React from "react";
14+
import dynamic from "next/dynamic";
15+
import ListSuggestion from "@/components/listSuggestion";
16+
import Loader from "@/components/loader";
17+
18+
const EmptyScreen = dynamic(() => import("@/components/emptyScreen"), {
19+
ssr: false,
20+
loading: () => <Loader />,
21+
});
1522

1623
export default function Home() {
17-
const [chatHistory, setChatHistory] = React.useState<Content[] | []>([]);
1824
const [message, setMessage] = React.useState<string | null>(null);
1925
const [isLoading, setIsLoading] = React.useState(false);
26+
const [error, setError] = React.useState<string | null>(null);
27+
const [commitChanges, setcommitChanges] = React.useState<string | null>(null);
28+
const [commitMessages, setcommitMessages] = React.useState<string | null>(
29+
null
30+
);
2031

2132
const { toast } = useToast();
2233

23-
const handelSubmit = async (e: React.FormEvent) => {
24-
e.preventDefault();
25-
26-
if (!message || message.trim() === "") {
34+
const handelSubmit = async ({ suggestion }: { suggestion: string }) => {
35+
if (suggestion === commitChanges) {
2736
toast({
28-
title: "Error",
29-
description: "Please enter a message",
37+
variant: "destructive",
38+
title: "Uh oh! Something went wrong.",
39+
description: "error: Please enter a different message.",
3040
});
3141
return;
3242
}
3343

3444
setIsLoading(true);
45+
setError(null);
3546

3647
try {
37-
setChatHistory((prevMsg) => [
38-
...prevMsg,
39-
{ role: "user", parts: [{ text: message! }] },
40-
]);
41-
42-
const data = await commitMessage({
43-
message: message!,
44-
history: chatHistory,
48+
const { data, error } = await commitChange({
49+
message: suggestion,
4550
});
4651

47-
if (data.success && data.text) {
48-
setChatHistory((prevMsg) => [
49-
...prevMsg,
50-
{ role: "model", parts: [{ text: data.text }] },
51-
]);
52+
if (error) {
53+
setError(error);
54+
toast({
55+
variant: "destructive",
56+
title: "Uh oh! Something went wrong.",
57+
description: error,
58+
action: (
59+
<button
60+
className={cn(
61+
toastVariants({
62+
variant: "destructive",
63+
className: "w-fit m-0 p-2 text-xs hover:bg-[#815305]/35",
64+
})
65+
)}
66+
onClick={() => handelSubmit({ suggestion })}
67+
>
68+
Try again
69+
</button>
70+
),
71+
});
5272
} else {
53-
console.log(data.error);
54-
if (data.error) {
55-
toast({
56-
description: data.error,
57-
});
58-
} else {
73+
if (data) {
74+
setcommitMessages(data.text);
75+
setcommitChanges(suggestion);
76+
setMessage("");
5977
}
6078
}
6179
} catch (error) {
6280
console.log(error);
6381
} finally {
6482
setIsLoading(false);
65-
setMessage("");
6683
}
6784
};
6885

86+
const submitForm = (
87+
e: React.FormEvent<HTMLFormElement>,
88+
message: string | null
89+
): void => {
90+
e.preventDefault();
91+
handelSubmit({ suggestion: message || "" });
92+
};
93+
6994
return (
70-
<main className="mx-10 lg:mx-20">
71-
<section className="h-screen py-10">
72-
<Navbar />
73-
<div className=" h-full py-10 flex items-center justify-center">
74-
<ScrollArea className="h-screen w-full">
75-
<div className="relative flex h-screen mx-0 sm:mx-10 lg:mx-60 flex-col p-4 lg:col-span-2">
76-
<ScrollArea className="w-full h-5/6 mb-2">
77-
<ListChat chatHistory={chatHistory} />
78-
{isLoading && <AiLoading />}
79-
</ScrollArea>
95+
<div className=" h-full py-10 flex items-center justify-center">
96+
<ScrollArea className="h-screen w-full">
97+
<div className=" flex h-screen mx-0 sm:mx-10 lg:mx-60 flex-col p-4 lg:col-span-2">
98+
<div className="w-full h-5/6 mb-2 flex items-end">
99+
<Card className="h-96 w-full flex justify-center items-center bg-primary-foreground/50">
100+
{error ? (
101+
<div>
102+
<h3 className="scroll-m-20 text-2xl font-semibold tracking-tight">
103+
Oops! Something Went Wrong!{" "}
104+
<span className="ml-2"> : ( </span>
105+
</h3>
106+
<p className="text-sm text-muted-foreground">{error}</p>
107+
</div>
108+
) : isLoading ? (
109+
<Loader />
110+
) : commitMessages ? (
111+
<ListSuggestion
112+
suggestions={commitMessages!}
113+
commitChanges={commitChanges || ""}
114+
/>
115+
) : (
116+
<EmptyScreen onSubmit={handelSubmit} />
117+
)}
118+
</Card>
119+
</div>
80120

81-
<div className="flex-1" />
82-
<form
83-
onSubmit={handelSubmit}
84-
className="relative overflow-hidden rounded-lg border bg-background focus-within:ring-1 focus-within:ring-ring"
121+
<div className="flex-1" />
122+
123+
<form
124+
onSubmit={(e) => submitForm(e, message)}
125+
className="relative overflow-hidden rounded-lg border bg-primary-foreground/50 focus-within:ring-1 focus-within:ring-ring"
126+
>
127+
<Label htmlFor="message" className="sr-only">
128+
Message
129+
</Label>
130+
<Input
131+
id="message"
132+
placeholder="Describe your changes here..."
133+
className="min-h-12 resize-none border-0 p-3 shadow-none focus-visible:ring-0 bg-primary-foreground/50"
134+
onChange={(e) => setMessage(e.target.value)}
135+
value={message || ""}
136+
disabled={isLoading}
137+
autoComplete="off"
138+
autoFocus
139+
required
140+
/>
141+
<div className="flex items-center p-3 pt-0">
142+
<Button
143+
type="submit"
144+
size="sm"
145+
className="ml-auto gap-1.5"
146+
disabled={isLoading}
85147
>
86-
<Label htmlFor="message" className="sr-only">
87-
Message
88-
</Label>
89-
<Input
90-
id="message"
91-
placeholder="Describe your changes here..."
92-
className="min-h-12 resize-none border-0 p-3 shadow-none focus-visible:ring-0"
93-
onChange={(e) => setMessage(e.target.value)}
94-
value={message!}
95-
disabled={isLoading}
96-
autoComplete="off"
97-
autoFocus
98-
required
99-
/>
100-
<div className="flex items-center p-3 pt-0">
101-
<Button
102-
type="submit"
103-
size="sm"
104-
className="ml-auto gap-1.5"
105-
disabled={isLoading}
106-
>
107-
Send Message
108-
<CornerDownLeft className="size-3.5" />
109-
</Button>
110-
</div>
111-
</form>
148+
Send Message
149+
<CornerDownLeft className="size-3.5" />
150+
</Button>
112151
</div>
113-
</ScrollArea>
152+
</form>
114153
</div>
115-
</section>
116-
</main>
154+
</ScrollArea>
155+
</div>
117156
);
118157
}

components/AiLoading.tsx

-13
This file was deleted.

0 commit comments

Comments
 (0)