commit
e567c2ba78
4 changed files with 80 additions and 45 deletions
|
|
@ -1,15 +1,27 @@
|
|||
import { PutObjectCommand, type S3Client } from "@aws-sdk/client-s3";
|
||||
import { PostgrestError, type SupabaseClient, type User } from "@supabase/supabase-js";
|
||||
import {
|
||||
PostgrestError,
|
||||
type SupabaseClient,
|
||||
type User,
|
||||
} from "@supabase/supabase-js";
|
||||
import { Hono } from "hono";
|
||||
import type { Transporter } from "nodemailer";
|
||||
import type { StreamChat } from "stream-chat";
|
||||
import { config } from "./config.js";
|
||||
import type { Tables } from "./database.types.ts";
|
||||
import { generateICSFromEvents, writeCalendarFileToR2 } from "./helpers.js";
|
||||
import { authMiddleware, r2Middleware, streamChatMiddleware } from "./middleware.js";
|
||||
import {
|
||||
authMiddleware,
|
||||
r2Middleware,
|
||||
streamChatMiddleware,
|
||||
} from "./middleware.js";
|
||||
import { generateToken } from "./token.js";
|
||||
import { transporter } from "./transporter.js";
|
||||
import type { EventAndTablo, EventInsertInTablo, TabloInsert } from "./types.ts";
|
||||
import type {
|
||||
EventAndTablo,
|
||||
EventInsertInTablo,
|
||||
TabloInsert,
|
||||
} from "./types.ts";
|
||||
|
||||
export const tabloRouter = new Hono<{
|
||||
Variables: {
|
||||
|
|
@ -166,7 +178,9 @@ tabloRouter.post("/create-and-invite", async (c) => {
|
|||
const { data: insertedTablo, error } = await supabase
|
||||
.from("tablos")
|
||||
.insert({
|
||||
name: `${invitedUserDataTyped.name || "Invité"} / ${ownerDataTyped.name || "Propriétaire"}`,
|
||||
name: `${invitedUserDataTyped.name || "Invité"} / ${
|
||||
ownerDataTyped.name || "Propriétaire"
|
||||
}`,
|
||||
color: "bg-blue-500",
|
||||
status: "todo",
|
||||
owner_id: ownerId,
|
||||
|
|
@ -184,20 +198,22 @@ tabloRouter.post("/create-and-invite", async (c) => {
|
|||
}
|
||||
|
||||
// Grant access to the current user (invited user) as a non-admin member
|
||||
const { error: tabloAccessError } = await supabase.from("tablo_access").insert(
|
||||
{
|
||||
tablo_id: tabloData.id,
|
||||
user_id: user.id,
|
||||
// ** IMPORTANT **
|
||||
is_admin: false,
|
||||
// -------------
|
||||
is_active: true,
|
||||
granted_by: ownerId,
|
||||
}
|
||||
// {
|
||||
// onConflict: "tablo_id, user_id",
|
||||
// }
|
||||
);
|
||||
const { error: tabloAccessError } = await supabase
|
||||
.from("tablo_access")
|
||||
.insert(
|
||||
{
|
||||
tablo_id: tabloData.id,
|
||||
user_id: user.id,
|
||||
// ** IMPORTANT **
|
||||
is_admin: false,
|
||||
// -------------
|
||||
is_active: true,
|
||||
granted_by: ownerId,
|
||||
}
|
||||
// {
|
||||
// onConflict: "tablo_id, user_id",
|
||||
// }
|
||||
);
|
||||
|
||||
if (tabloAccessError) {
|
||||
console.error("tabloAccessError", tabloAccessError);
|
||||
|
|
@ -290,7 +306,8 @@ tabloRouter.patch("/update", async (c) => {
|
|||
|
||||
const updatedTablo = update as Tables<"tablos">;
|
||||
|
||||
const isUpdatingName = tablo.name !== undefined && tablo.name !== updatedTablo.name;
|
||||
const isUpdatingName =
|
||||
tablo.name !== undefined && tablo.name !== updatedTablo.name;
|
||||
|
||||
if (error) {
|
||||
return c.json({ error: error.message }, 500);
|
||||
|
|
@ -344,7 +361,6 @@ tabloRouter.delete("/delete", async (c) => {
|
|||
tabloRouter.post("/invite", async (c) => {
|
||||
const sender = c.get("user");
|
||||
const supabase = c.get("supabase");
|
||||
const transporter = c.get("transporter");
|
||||
const { email: recipientmail, tablo_id } = await c.req.json();
|
||||
|
||||
const token = generateToken();
|
||||
|
|
@ -366,7 +382,10 @@ tabloRouter.post("/invite", async (c) => {
|
|||
}
|
||||
|
||||
if (tablo.owner_id !== sender.id) {
|
||||
return c.json({ error: "You are not allowed to invite users to this tablo" }, 400);
|
||||
return c.json(
|
||||
{ error: "You are not allowed to invite users to this tablo" },
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
const { error } = await supabase.from("tablo_invites").insert({
|
||||
|
|
@ -386,7 +405,9 @@ tabloRouter.post("/invite", async (c) => {
|
|||
subject: "Vous avez été invité à un tablo",
|
||||
html: `<p>Vous avez été invité à un tablo avec <a href="${
|
||||
config.XTABLO_URL
|
||||
}/join/${encodeURIComponent(tablo.name)}?token=${encodeURIComponent(token)}">ce lien</a></p>`,
|
||||
}/join/${encodeURIComponent(tablo.name)}?token=${encodeURIComponent(
|
||||
token
|
||||
)}">ce lien</a></p>`,
|
||||
});
|
||||
|
||||
return c.json({
|
||||
|
|
@ -419,15 +440,17 @@ tabloRouter.post("/join", async (c) => {
|
|||
|
||||
const { id: invite_id, tablo_id, invited_by } = inviteData;
|
||||
|
||||
const { error: tabloAccessError } = await supabase.from("tablo_access").insert({
|
||||
tablo_id,
|
||||
user_id: joiner.id,
|
||||
// ** IMPORTANT **
|
||||
is_admin: false,
|
||||
// -------------
|
||||
is_active: true,
|
||||
granted_by: invited_by,
|
||||
});
|
||||
const { error: tabloAccessError } = await supabase
|
||||
.from("tablo_access")
|
||||
.insert({
|
||||
tablo_id,
|
||||
user_id: joiner.id,
|
||||
// ** IMPORTANT **
|
||||
is_admin: false,
|
||||
// -------------
|
||||
is_active: true,
|
||||
granted_by: invited_by,
|
||||
});
|
||||
|
||||
if (tabloAccessError) {
|
||||
console.error("tabloAccessError", tabloAccessError);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { config } from "./config.js";
|
|||
|
||||
const OAuth2 = google.auth.OAuth2;
|
||||
|
||||
export const createTransporter = async () => {
|
||||
export const createTransporter = () => {
|
||||
const oauth2Client = new OAuth2(
|
||||
config.EMAIL_CLIENT_ID,
|
||||
config.EMAIL_CLIENT_SECRET,
|
||||
|
|
@ -31,4 +31,4 @@ export const createTransporter = async () => {
|
|||
return transporter;
|
||||
};
|
||||
|
||||
export const transporter = await createTransporter();
|
||||
export const transporter = createTransporter();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const TabloModal = ({ tablo, onClose, onEdit }: TabloModalProps) => {
|
|||
const [showMembers, setShowMembers] = useState(false);
|
||||
|
||||
const [inviteEmail, setInviteEmail] = useState("");
|
||||
const inviteUser = useInviteUser();
|
||||
const { mutate: inviteUser, isPending: isInvitingUser } = useInviteUser();
|
||||
|
||||
const {
|
||||
data: fileData,
|
||||
|
|
@ -425,14 +425,20 @@ export const TabloModal = ({ tablo, onClose, onEdit }: TabloModalProps) => {
|
|||
placeholder="Email de l'utilisateur à inviter"
|
||||
className="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSendInvite}
|
||||
disabled={!isEmailValid(inviteEmail)}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed rounded-md transition-colors"
|
||||
>
|
||||
Inviter
|
||||
</button>
|
||||
{isInvitingUser ? (
|
||||
<div className="flex justify-center items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500"></div>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSendInvite}
|
||||
disabled={!isEmailValid(inviteEmail)}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed rounded-md transition-colors"
|
||||
>
|
||||
Inviter
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,14 @@ import { toast } from "@ui/ui-library/toast/toast-queue";
|
|||
// Invite user by email
|
||||
export const useInviteUser = () => {
|
||||
const { session } = useSession();
|
||||
const { mutate } = useMutation({
|
||||
mutationFn: async ({ email, tablo_id }: { email: string; tablo_id: string }) => {
|
||||
const { mutate, isPending } = useMutation({
|
||||
mutationFn: async ({
|
||||
email,
|
||||
tablo_id,
|
||||
}: {
|
||||
email: string;
|
||||
tablo_id: string;
|
||||
}) => {
|
||||
const { data } = await api.post(
|
||||
"/api/v1/tablos/invite",
|
||||
{
|
||||
|
|
@ -35,7 +41,7 @@ export const useInviteUser = () => {
|
|||
);
|
||||
},
|
||||
});
|
||||
return mutate;
|
||||
return { mutate, isPending };
|
||||
};
|
||||
|
||||
export const useJoinTablo = () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue