Skip to content

Commit

Permalink
Logsnag
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusab committed Jan 3, 2024
1 parent c8ce920 commit 7769efa
Show file tree
Hide file tree
Showing 24 changed files with 375 additions and 187 deletions.
4 changes: 3 additions & 1 deletion .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ GOCARDLESS_SECRET_KEY=
KV_REST_API_URL=
KV_REST_API_TOKEN=
NOVU_API_KEY=
NEXT_PUBLIC_TRIGGER_API_KEY=
NEXT_PUBLIC_TRIGGER_API_KEY=
LOGSNAG_TOKEN=
LOGSNAG_PROJECT=
7 changes: 4 additions & 3 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@hookform/resolvers": "^3.3.3",
"@logsnag/next": "^1.0.2",
"@midday/gocardless": "workspace:*",
"@midday/jobs": "workspace:*",
"@midday/kv": "workspace:*",
Expand All @@ -22,16 +23,16 @@
"@midday/supabase": "workspace:*",
"@midday/ui": "workspace:*",
"@novu/headless": "^0.22.0",
"@tanstack/react-table": "^8.11.2",
"@tanstack/react-table": "^8.11.3",
"@todesktop/client-core": "^1.2.3",
"@trigger.dev/nextjs": "^2.3.8",
"@trigger.dev/nextjs": "^2.3.9",
"@uidotdev/usehooks": "^2.4.1",
"@vercel/edge-config": "^0.4.1",
"@vercel/speed-insights": "^1.0.2",
"@zip.js/zip.js": "2.7.32",
"change-case": "^5.3.0",
"fast-csv": "^4.3.6",
"framer-motion": "^10.17.0",
"framer-motion": "^10.17.4",
"ms": "^2.1.3",
"next": "14.0.4",
"next-international": "^1.1.4",
Expand Down
32 changes: 32 additions & 0 deletions apps/dashboard/src/actions/accept-invite-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use server";

import { getUser } from "@midday/supabase/cached-queries";
import { createClient } from "@midday/supabase/server";
import { revalidateTag } from "next/cache";
import { action } from "./safe-action";
import { acceptInviteSchema } from "./schema";

export const acceptInviteAction = action(acceptInviteSchema, async ({ id }) => {
const supabase = createClient();
const user = await getUser();

const { data: inviteData } = await supabase
.from("user_invites")
.select("*")
.eq("id", id)
.single();

await supabase.from("users_on_team").insert({
user_id: user.data.id,
role: inviteData.role,
team_id: inviteData.team_id,
});

await supabase.from("user_invites").delete().eq("id", id);

revalidateTag(`team_invites_${user.data.team_id}`);
revalidateTag(`user_invites_${user.data.email}`);
revalidateTag(`teams_${user.data.id}`);

return id;
});
3 changes: 2 additions & 1 deletion apps/dashboard/src/actions/change-team-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { updateUser } from "@midday/supabase/mutations";
import { createClient } from "@midday/supabase/server";
import { revalidateTag } from "next/cache";
import { redirect } from "next/navigation";
import { action } from "./safe-action";
import { changeTeamSchema } from "./schema";

Expand All @@ -12,5 +13,5 @@ export const changeTeamAction = action(changeTeamSchema, async ({ teamId }) => {

revalidateTag(`user_${user.data.id}`);

return teamId;
redirect("/");
});
23 changes: 23 additions & 0 deletions apps/dashboard/src/actions/decline-invite-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use server";

import { getUser } from "@midday/supabase/cached-queries";
import { createClient } from "@midday/supabase/server";
import { revalidateTag } from "next/cache";
import { action } from "./safe-action";
import { declineInviteSchema } from "./schema";

export const declineInviteAction = action(
declineInviteSchema,
async ({ id }) => {
const supabase = createClient();
const user = await getUser();

console.log(id);

// await supabase.from("user_invites").delete().eq("id", id);

revalidateTag(`team_invites_${user.data.team_id}`);

return id;
}
);
16 changes: 14 additions & 2 deletions apps/dashboard/src/actions/invite-team-members-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@

import { env } from "@/env.mjs";
import InviteEmail from "@midday/email/emails/invite";
import { getI18n } from "@midday/email/locales";
import { getUser } from "@midday/supabase/cached-queries";
import { createClient } from "@midday/supabase/server";
import { renderAsync } from "@react-email/components";
import { revalidatePath } from "next/cache";
import { revalidateTag } from "next/cache";
import { headers } from "next/headers";
import { Resend } from "resend";
import { action } from "./safe-action";
import { inviteTeamMembersSchema } from "./schema";

const resend = new Resend(env.RESEND_API_KEY);
import { headers } from "next/headers";

export const inviteTeamMembersAction = action(
inviteTeamMembersSchema,
async ({ invites }) => {
const supabase = createClient();
const user = await getUser();

const { t } = getI18n({ locale: user.data.locale });

const location = headers().get("x-vercel-ip-city") ?? "Unknown";
const ip = headers().get("x-forwarded-for") ?? "127.0.0.1";

Expand All @@ -40,7 +43,15 @@ export const inviteTeamMembersAction = action(
const emails = invtesData.map(async (invites) => ({
from: "Midday <middaybot@midday.ai>",
to: [invites.email],
subject: `${invites.user.full_name} invited you to the ${invites.team.name} team on Midday`,
subject: t(
{
id: "invite.subject",
},
{
invitedByName: invites.user.full_name,
teamName: invites.team.name,
}
),
html: await renderAsync(
InviteEmail({
invitedByEmail: invites.user.email,
Expand All @@ -50,6 +61,7 @@ export const inviteTeamMembersAction = action(
inviteCode: invites.code,
ip,
location,
locale: user.data.locale,
})
),
}));
Expand Down
44 changes: 21 additions & 23 deletions apps/dashboard/src/actions/leave-team-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,33 @@ import { getTeamMembers, getUser } from "@midday/supabase/cached-queries";
import { leaveTeam } from "@midday/supabase/mutations";
import { createClient } from "@midday/supabase/server";
import { revalidateTag } from "next/cache";
import { redirect } from "next/navigation";
import { action } from "./safe-action";
import { leaveTeamSchema } from "./schema";

export const leaveTeamAction = action(leaveTeamSchema, async ({ teamId }) => {
const supabase = createClient();
const user = await getUser();
const { data: teamMembersData } = await getTeamMembers();
export const leaveTeamAction = action(
leaveTeamSchema,
async ({ teamId, role }) => {
const supabase = createClient();
const user = await getUser();
const { data: teamMembersData } = await getTeamMembers();

const totalOwners = teamMembersData.filter(
(member) => member.role === "owner"
).length;
const totalOwners = teamMembersData.filter(
(member) => member.role === "owner"
).length;

if (totalOwners === 1) {
throw Error("Action not allowed");
}
if (role === "owner" && totalOwners === 1) {
throw Error("Action not allowed");
}

const { data } = await leaveTeam(supabase, {
teamId,
userId: user.data.id,
});
const { data } = await leaveTeam(supabase, {
teamId,
userId: user.data.id,
});

revalidateTag(`team_members_${data.team_id}`);
revalidateTag(`user_${user.data.id}`);
revalidateTag(`teams_${user.data.id}`);
revalidateTag(`team_members_${data.team_id}`);
revalidateTag(`user_${user.data.id}`);
revalidateTag(`teams_${user.data.id}`);

if (data) {
redirect("/teams");
return data;
}

return data;
});
);
3 changes: 3 additions & 0 deletions apps/dashboard/src/actions/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export const deleteTeamMemberSchema = z.object({

export const leaveTeamSchema = z.object({
teamId: z.string(),
role: z.enum(["owner", "member"]),
});

export const deleteTeamSchema = z.object({
Expand All @@ -180,3 +181,5 @@ export type InviteTeamMembersFormValues = z.infer<
>;

export const deleteInviteSchema = z.object({ id: z.string() });
export const acceptInviteSchema = z.object({ id: z.string() });
export const declineInviteSchema = z.object({ id: z.string() });
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { TeamsTable } from "@/components/tables/teams/table";
import { getTeams } from "@midday/supabase/cached-queries";
import { getTeams, getUserInvites } from "@midday/supabase/cached-queries";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Teams | Midday",
};

export default async function Teams() {
const { data } = await getTeams();
const { data: teamsData } = await getTeams();
const { data: invitesData } = await getUserInvites();

return (
<div className="space-y-12">
<TeamsTable data={data} />
<TeamsTable
data={[
...teamsData,
...invitesData.map((invite) => ({ ...invite, isInvite: true })),
]}
/>
</div>
);
}
23 changes: 21 additions & 2 deletions apps/dashboard/src/components/modals/invite-team-members-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,31 @@ import {
SelectTrigger,
SelectValue,
} from "@midday/ui/select";
import { useToast } from "@midday/ui/use-toast";
import { Loader2 } from "lucide-react";
import { useAction } from "next-safe-action/hook";
import { useFieldArray, useForm } from "react-hook-form";

export function InviteTeamMembersModal() {
const inviteMembers = useAction(inviteTeamMembersAction);
export function InviteTeamMembersModal({ onOpenChange }) {
const { toast } = useToast();

const inviteMembers = useAction(inviteTeamMembersAction, {
onSuccess: () => {
onOpenChange(false);

toast({
title: "Successfully invited Team Members.",
duration: 3500,
});
},
onError: () => {
toast({
duration: 3500,
variant: "error",
title: "Something went wrong pleaase try again.",
});
},
});

const form = useForm<InviteTeamMembersFormValues>({
resolver: zodResolver(inviteTeamMembersSchema),
Expand Down
Loading

0 comments on commit 7769efa

Please sign in to comment.