diff --git a/auth.config.mjs b/auth.config.mjs index 024d8ca..c9b8c61 100644 --- a/auth.config.mjs +++ b/auth.config.mjs @@ -2,6 +2,13 @@ import Slack from "@auth/core/providers/slack"; import { defineConfig } from "auth-astro"; import { db, like, and, User, Organization } from "astro:db"; +import { LogSnag } from "logsnag"; + +const logsnag = new LogSnag({ + token: process.env.LOGSNAG_TOKEN || "", + project: "magicsnap", +}); + export default defineConfig({ providers: [ Slack({ @@ -9,6 +16,7 @@ export default defineConfig({ clientSecret: import.meta.env.SLACK_CLIENT_SECRET, checks: ["pkce", "nonce"], async profile(profile) { + let newUser = false; profile["https://slack.com/team_id"] = "slack-" + profile["https://slack.com/team_id"]; @@ -49,7 +57,43 @@ export default defineConfig({ role: "admin", }); - role[0] = { role: "admin" }; + await logsnag.track({ + channel: "signups", + event: "signup", + user_id: profile["https://slack.com/user_id"], + description: "User signed up as an admin", + icon: "🚀", + tags: { + team: profile["https://slack.com/team_id"], + role: "admin", + }, + }); + + await logsnag.track({ + channel: "actions", + event: "joined_team", + user_id: profile["https://slack.com/user_id"], + description: "User joined a team", + icon: "🤝", + tags: { + team: profile["https://slack.com/team_id"], + role: "admin", + }, + }); + + await logsnag.identify({ + user_id: profile["https://slack.com/user_id"], + properties: { + email: profile.email, + name: profile.name, + image: profile.picture, + team: profile["https://slack.com/team_id"], + role: "admin", + }, + }); + + role[0].role = "admin"; + newUser = true; } else { await db.insert(User).values({ userId: profile["https://slack.com/user_id"], @@ -60,10 +104,69 @@ export default defineConfig({ role: "user", }); - role[0] = { role: "user" }; + await logsnag.track({ + channel: "signups", + event: "signup", + user_id: profile["https://slack.com/user_id"], + description: "User signed up as a user", + icon: "🚀", + tags: { + team: profile["https://slack.com/team_id"], + role: "user", + }, + }); + + await logsnag.track({ + channel: "actions", + event: "joined_team", + user_id: profile["https://slack.com/user_id"], + description: "User joined a team", + icon: "🤝", + tags: { + team: profile["https://slack.com/team_id"], + role: "user", + }, + }); + + await logsnag.identify({ + user_id: profile["https://slack.com/user_id"], + properties: { + email: profile.email, + name: profile.name, + image: profile.picture, + team: profile["https://slack.com/team_id"], + role: "user", + }, + }); + + role[0].role = "user"; + newUser = true; } } else { - role[0] = { role: "guest" }; + role[0].role = "guest"; + + await logsnag.track({ + channel: "signups", + event: "signup", + user_id: profile["https://slack.com/user_id"], + description: "User signed up as a guest", + icon: "🚀", + tags: { + team: profile["https://slack.com/team_id"], + role: "guest", + }, + }); + + await logsnag.identify({ + user_id: profile["https://slack.com/user_id"], + properties: { + email: profile.email, + name: profile.name, + image: profile.picture, + team: profile["https://slack.com/team_id"], + role: "guest", + }, + }); } } @@ -75,7 +178,8 @@ export default defineConfig({ team: profile["https://slack.com/team_id"], teamName: profile["https://slack.com/team_name"], teamImage: profile["https://slack.com/team_image_230"], - role: role[0].role || "user", + role: role[0].role || "guest", + newUser: newUser, }; }, }), @@ -89,6 +193,7 @@ export default defineConfig({ token.teamImage = user.teamImage; token.role = user.role; token.id = user.id; + token.newUser = user.newUser; } return token; }, @@ -100,6 +205,7 @@ export default defineConfig({ session.teamImage = token.teamImage; session.user.role = token.role; session.user.id = token.id; + session.newUser = token.newUser; } return session; }, diff --git a/bun.lockb b/bun.lockb index 048c98c..94f70ea 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/db/config.ts b/db/config.ts index 7a382e3..6afc52a 100644 --- a/db/config.ts +++ b/db/config.ts @@ -20,6 +20,7 @@ const User = defineTable({ email: column.text(), image: column.text(), role: column.text(), + allergies: column.text({ optional: true }), }, indexes: { userIdx: { on: ["userId"], unique: true }, diff --git a/package.json b/package.json index b96307e..d994371 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,12 @@ "@astrojs/node": "^8.2.5", "@astrojs/tailwind": "^5.1.0", "@auth/core": "^0.18.6", + "@types/canvas-confetti": "^1.6.4", "astro": "^4.5.10", "auth-astro": "^4.1.1", + "canvas-confetti": "^1.9.2", "jwt-decode": "^4.0.0", + "logsnag": "^1.0.0", "magick.css": "^1.0.5", "normalize.css": "^8.0.1", "prettier": "^3.2.5", diff --git a/src/pages/api/remind.ts b/src/pages/api/remind.ts index d90005d..4feeb07 100644 --- a/src/pages/api/remind.ts +++ b/src/pages/api/remind.ts @@ -1,5 +1,11 @@ import type { APIRoute } from "astro" import { db, User, Organization, Event } from "astro:db"; +import { LogSnag } from "logsnag"; + +const logsnag = new LogSnag({ + token: process.env.LOGSNAG_TOKEN || "", + project: "magicsnap", +}); export const POST: APIRoute = async ({ request }) => { // get authorization header @@ -20,6 +26,13 @@ export const POST: APIRoute = async ({ request }) => { return diffHours < 24 && diffHours > 0 }) + await logsnag.track({ + channel: "api", + event: "reminder-sent", + description: `Sent reminder to ${users.length} users in ${organizations.length} different organizations about ${eventsHappeningToday.length} events happening today`, + icon: "📬", + }); + return new Response(JSON.stringify({ ok: true, eventsHappeningToday: eventsHappeningToday, users: users, organizations: organizations }), { status: 200 }) diff --git a/src/pages/dashboard.astro b/src/pages/dashboard.astro index fadbddc..cf63494 100644 --- a/src/pages/dashboard.astro +++ b/src/pages/dashboard.astro @@ -13,6 +13,7 @@ type ExtendedSession = { user: { role: string; }; + newUser: boolean; }; const session = (await getSession(Astro.request)) as Session & ExtendedSession; @@ -44,6 +45,13 @@ if (!session) { }); } +import { LogSnag } from "logsnag"; + +const logsnag = new LogSnag({ + token: process.env.LOGSNAG_TOKEN || "", + project: "magicsnap", +}); + import { db, Event, User } from "astro:db"; import { like } from "astro:db"; @@ -102,6 +110,13 @@ if (Astro.request.method === "POST") { statusNotGoing: statusNotGoing.join(","), }) .where(like(Event.id, eventID)); + + await logsnag.track({ + channel: "actions", + event: "event_status_change", + icon: "📅", + user_id: session.user.id, + }); } } else if (data.get("delete") != null) { if (session.user.role != "admin") { @@ -110,6 +125,13 @@ if (Astro.request.method === "POST") { const eventID = data.get("eventID") as string; await db.delete(Event).where(like(Event.id, eventID)); + + await logsnag.track({ + channel: "actions", + event: "event_delete", + icon: "📅", + user_id: session.user.id, + }); } else if (data.get("newEvent") != null) { if (!data.has("name") || !data.has("date") || !data.has("time") || !data.has("location") || !data.has("comments")) { @@ -135,6 +157,13 @@ if (Astro.request.method === "POST") { .join(","), }; await db.insert(Event).values(event); + + await logsnag.track({ + channel: "actions", + event: "event_create", + icon: "📅", + user_id: session.user.id, + }); } } catch (error) { if (error instanceof Error) { @@ -165,6 +194,13 @@ const users = await db.select().from(User).where(like(User.team, session.team)); } events

+ { + session.newUser && ( +
+

Since you are a new user we recommend that you first fillout your allergies here then come back and set your availability!

+
+ ) + } { session.user.role === "admin" && (
diff --git a/src/pages/join/[joinCode].astro b/src/pages/join/[joinCode].astro index 85c628c..8667ff0 100644 --- a/src/pages/join/[joinCode].astro +++ b/src/pages/join/[joinCode].astro @@ -4,10 +4,14 @@ import { SignIn } from "auth-astro/components"; import { getSession } from "auth-astro/server"; import { type Session } from "@auth/core/types"; -import { db } from "astro:db"; -import { Invite } from "astro:db"; -import { like } from "astro:db"; -import { Organization } from "astro:db"; +import { db, like, Event, Invite, Organization } from "astro:db"; + +import { LogSnag } from "logsnag"; + +const logsnag = new LogSnag({ + token: process.env.LOGSNAG_TOKEN || "", + project: "magicsnap", +}); type ExtendedSession = { team: string; @@ -75,6 +79,23 @@ if (session && session.user.role === "guest") { name: session.teamName, image: session.teamImage, }); + await db.insert(Event).values({ + name: "Welcome to MagicSnap! 🎉", + date: new Date(Date.now() + 1000 * 60 * 60 * 2), + team: session.team, + comments: "A default event created by workspace connection", + location: "MagicSnap", + statusGoing: session.user.id, + statusNotGoing: "", + statusMaybe: "", + }); + await logsnag.track({ + channel: "join-code", + event: "create-team", + icon: "🪄", + user_id: session.user.id, + notify: true, + }); } --- @@ -104,7 +125,7 @@ if (session && session.user.role === "guest") { { session && session.user.role === "guest" && ( <> -
+

You have successfully connected your team {team.teamName} to MagicSnap! You can now sign in to MagicSnap using your account and @@ -121,6 +142,63 @@ if (session && session.user.role === "guest") { } + +