diff --git a/app/[locale]/(auth)/sign-in/components/LoginComponent.tsx b/app/[locale]/(auth)/sign-in/components/LoginComponent.tsx index 768f15c..0e243a7 100644 --- a/app/[locale]/(auth)/sign-in/components/LoginComponent.tsx +++ b/app/[locale]/(auth)/sign-in/components/LoginComponent.tsx @@ -106,7 +106,7 @@ export function LoginComponent() { }); } if (status?.ok) { - console.log("Status OK"); + // console.log("Status OK"); toast({ description: "Login successful.", }); diff --git a/app/[locale]/(routes)/components/Feedback.tsx b/app/[locale]/(routes)/components/Feedback.tsx index 40c2c1b..9bd7233 100644 --- a/app/[locale]/(routes)/components/Feedback.tsx +++ b/app/[locale]/(routes)/components/Feedback.tsx @@ -14,7 +14,7 @@ const Feedback = () => { const [open, setOpen] = useState(false); return ( - + diff --git a/app/[locale]/(routes)/components/Header.tsx b/app/[locale]/(routes)/components/Header.tsx index 7a1fcb7..82fb453 100644 --- a/app/[locale]/(routes)/components/Header.tsx +++ b/app/[locale]/(routes)/components/Header.tsx @@ -1,14 +1,11 @@ -import { CommandComponent } from "@/components/CommandComponent"; +import Feedback from "./Feedback"; +import FulltextSearch from "./FulltextSearch"; import AvatarDropdown from "./ui/AvatarDropdown"; -import { ThemeToggle } from "@/components/ThemeToggle"; import { Separator } from "@/components/ui/separator"; - import { SetLanguage } from "@/components/SetLanguage"; -import FulltextSearch from "./FulltextSearch"; -import Link from "next/link"; -import { GithubIcon } from "lucide-react"; -import Feedback from "./Feedback"; +import { ThemeToggle } from "@/components/ThemeToggle"; +import { CommandComponent } from "@/components/CommandComponent"; type Props = { id: string; @@ -30,12 +27,13 @@ const Header = ({ id, name, email, avatar, lang }: Props) => { -
-
{name}
-
{email}
-
Language: {lang}
-
- +
+ diff --git a/app/[locale]/(routes)/components/ui/AvatarDropdown.tsx b/app/[locale]/(routes)/components/ui/AvatarDropdown.tsx index 23dfa28..03770fd 100644 --- a/app/[locale]/(routes)/components/ui/AvatarDropdown.tsx +++ b/app/[locale]/(routes)/components/ui/AvatarDropdown.tsx @@ -1,4 +1,5 @@ "use client"; + import React from "react"; import { Avatar, AvatarImage } from "@/components/ui/avatar"; import { @@ -9,16 +10,21 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { signOut, useSession } from "next-auth/react"; +import { signOut } from "next-auth/react"; import Link from "next/link"; -import { Settings } from "lucide-react"; +import { LogOut, Settings } from "lucide-react"; +import { useRouter } from "next/navigation"; type Props = { avatar: string; userId: string; + name: string; + email: string; }; -const AvatarDropdown = ({ avatar, userId }: Props) => { +const AvatarDropdown = ({ avatar, userId, name, email }: Props) => { + const router = useRouter(); + return ( @@ -33,24 +39,29 @@ const AvatarDropdown = ({ avatar, userId }: Props) => { - My Account + +
{name}
+
{email}
+
+ - - Todo dashboard + router.push("/projects/dashboard")}> + Todo dashboard - - CRM dashboard + router.push(`/crm/dashboard/${userId}`)} + > + Sales dashboard - - - - Profile - + router.push("/profile")}> + + Profile settings - -
signOut()}>Sign out
+ signOut()}> + + Sign out
diff --git a/app/[locale]/(routes)/invoice/detail/[invoiceId]/page.tsx b/app/[locale]/(routes)/invoice/detail/[invoiceId]/page.tsx index 28df970..7fe47f6 100644 --- a/app/[locale]/(routes)/invoice/detail/[invoiceId]/page.tsx +++ b/app/[locale]/(routes)/invoice/detail/[invoiceId]/page.tsx @@ -1,6 +1,8 @@ import React from "react"; import Container from "../../../components/ui/Container"; import { getInvoice } from "@/actions/invoice/get-invoice"; +import { MessageCircle, MessagesSquare } from "lucide-react"; +import InvoiceChat from "../_dialogs/InvoiceChat"; interface InvoiceDetailProps { params: { invoiceId: string }; @@ -12,7 +14,24 @@ const InvoiceDetailPage = async ({ params }: InvoiceDetailProps) => { return ( -
{JSON.stringify(invoiceData, null, 2)}
+
+
+ +
+
+ +
+
+
{JSON.stringify(invoiceData, null, 2)}
+
+
); }; diff --git a/app/[locale]/(routes)/invoice/detail/_dialogs/InvoiceChat.tsx b/app/[locale]/(routes)/invoice/detail/_dialogs/InvoiceChat.tsx new file mode 100644 index 0000000..a6d7a43 --- /dev/null +++ b/app/[locale]/(routes)/invoice/detail/_dialogs/InvoiceChat.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { MessagesSquare } from "lucide-react"; + +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; + +const InvoiceChat = () => { + return ( + + + + + + + Invoice conversation + + content here - in progress + + + ); +}; + +export default InvoiceChat; diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..eea7237 --- /dev/null +++ b/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,7 @@ +import NextAuth from "next-auth"; + +import { authOptions } from "@/lib/auth"; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; diff --git a/components/CommandComponent.tsx b/components/CommandComponent.tsx index 045b569..18e9e74 100644 --- a/components/CommandComponent.tsx +++ b/components/CommandComponent.tsx @@ -37,8 +37,13 @@ export function CommandComponent() { if (e.key === "Escape") { setOpen(false); } - if (e.key === "p" && e.metaKey) { + if (e.key === "D" && e.metaKey && e.shiftKey) { + router.push("/"); + setOpen(false); + } + if (e.key === "P" && e.metaKey && e.shiftKey) { router.push("/profile"); + setOpen(false); } if (e.key === "k" && e.metaKey) { signOut(); @@ -47,7 +52,7 @@ export function CommandComponent() { document.addEventListener("keydown", down); return () => document.removeEventListener("keydown", down); - }, []); + }, [router]); return (
@@ -77,10 +82,15 @@ export function CommandComponent() { + redirect("/")}> + + Dashboard + Shift + ⌘ + D + redirect("/profile")}> Profile - ⌘P + Shift + ⌘ + P diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts deleted file mode 100644 index f9a6347..0000000 --- a/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,5 +0,0 @@ -import { authOptions } from "@/lib/auth"; -import NextAuth from "next-auth"; - -// @see @/lib/auth -export default NextAuth(authOptions); diff --git a/pages/api/cron/demo.ts b/pages/api/cron/demo.ts deleted file mode 100644 index 87c34b4..0000000 --- a/pages/api/cron/demo.ts +++ /dev/null @@ -1,20 +0,0 @@ -import sendEmail from "@/lib/sendmail"; -import { NextApiResponse } from "next"; - -export default async function handler(res: NextApiResponse) { - try { - const message: string = `Hi, Iam ${process.env.NEXT_PUBLIC_APP_NAME} API Bot which will send you some info if you want! I am running on ${process.env.NEXT_PUBLIC_APP_URL}`; - - await sendEmail({ - from: process.env.EMAIL_FROM, - to: "info@softbase.cz", - subject: `${process.env.NEXT_PUBLIC_APP_NAME} Cron`, - text: message, - }); - - return res.status(200).end("Hello Cron!"); - } catch (error: any) { - console.log(error); - return res.status(500).end(error.message); - } -} diff --git a/pages/api/cron/sendTaskNotify/index.ts b/pages/api/cron/sendTaskNotify/index.ts deleted file mode 100644 index c984d76..0000000 --- a/pages/api/cron/sendTaskNotify/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* -This API endpoint is used to add a new task to a section. -*/ -import sendEmail from "@/lib/sendmail"; -import { prismadb } from "@/lib/prisma"; -import dayjs from "dayjs"; -import { NextApiRequest, NextApiResponse } from "next"; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - try { - const today = dayjs().startOf("day"); - const nextWeek = dayjs().add(7, "day").startOf("day"); - let prompt = ""; - - const users = await prismadb.users.findMany({ - where: { - userStatus: "ACTIVE", - }, - }); - - if (!users) { - return res.status(201).json("No users found"); - } - - for (const user of users) { - const getTaskPastDue = await prismadb.tasks.findMany({ - where: { - AND: [ - { - user: user.id, - }, - { - dueDateAt: { - lte: new Date(), - }, - }, - ], - }, - }); - - const getTaskPastDueInSevenDays = await prismadb.tasks.findMany({ - where: { - AND: [ - { - user: user.id, - }, - { - dueDateAt: { - //lte: dayjs().add(7, "day").toDate(), - gt: today.toDate(), // Due date is greater than or equal to today - lt: nextWeek.toDate(), // Due date is less than next week (not including today) - }, - }, - ], - }, - }); - - //console.log(user.userLanguage, "users.userLanguage"); - switch (user.userLanguage) { - case "en": - prompt = `Hi, Iam ${process.env.NEXT_PUBLIC_APP_URL} API Bot. - \n\n - There are ${getTaskPastDue.length} tasks past due and ${ - getTaskPastDueInSevenDays.length - } tasks due in the next 7 days. - \n\n - Details today tasks: ${JSON.stringify(getTaskPastDue, null, 2)} - \n\n - Details next 7 days tasks: ${JSON.stringify( - getTaskPastDueInSevenDays, - null, - 2 - )} - \n\n - As a personal assistant, write a message to ${ - user.name - } to remind them of their tasks. And also dont forget to send them a some positive vibes. - \n\n - `; - break; - case "cz": - prompt = `Jako profesionální asistentka Emma s perfektní znalostí projektového řízení, který má na starosti projekty na adrese${ - process.env.NEXT_PUBLIC_APP_URL - }, připrave manažerské shrnutí o úkolech včetně jejich detailů a termínů. Vše musí být perfektně česky a výstižně. - \n\n - Zde jsou informace k úkolům: - \n\n - Informace o projektu: Počet úkolů které jsou k řešení dnes: ${ - getTaskPastDue.length - }, Počet úkolů, které musí být vyřešeny nejpozději do sedmi dnů: ${ - getTaskPastDueInSevenDays.length - }. - \n\n - Detailní informace v JSON formátu k úkolům, které musí být hotové dnes: ${JSON.stringify( - getTaskPastDue, - null, - 2 - )} - \n\n - Detailní informace k úkolům, které musí být hotové během následujících sedmi dní: ${JSON.stringify( - getTaskPastDueInSevenDays, - null, - 2 - )} - - \n\n - Na konec napiš manažerské shrnutí včetně milého uvítání napiš pro uživatele: ${ - user.name - } a přidej odkaz ${ - process.env.NEXT_PUBLIC_APP_URL + "/projects/dashboard" - } jako odkaz na detail k úkolům . Na konci manažerského shrnutí přidej. 1 tip na manažerskou dovednost z oblasti projektového řízení a timemanagementu, 2-3 věty s pozitivním naladěním a podporou, nakonec popřej hezký pracovní den a infomaci, že tato zpráva byla vygenerována pomocí umělé inteligence OpenAi. - \n\n - `; - break; - } - - const getAiResponse = await fetch( - `${process.env.NEXT_PUBLIC_APP_URL}/api/openai/createChatCompletion`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - prompt: prompt, - }), - } - ).then((res) => res.json()); - - if (!user.email) { - return res.status(201).json("No user email found"); - } - - await sendEmail({ - from: process.env.EMAIL_FROM, - to: user.email, - subject: `${process.env.NEXT_PUBLIC_APP_NAME} OpenAI Project manager assistant`, - text: getAiResponse.response, - }); - } - - return res.status(201).json("Success"); - //TODO: Fix this - } catch (error: any) { - //console.log(error); - return res.status(500).json({ error: error.message }); - } -}