Skip to content

Commit 7f53e07

Browse files
authored
Merge pull request #96 from tracet2t/86ewz6m3u-tankstack_provider
Tankstack Query Provider
2 parents f4028ec + a32a530 commit 7f53e07

File tree

22 files changed

+1306
-130
lines changed

22 files changed

+1306
-130
lines changed

docs/api/API_INVITATIONS.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Invitations API Documentation
2+
3+
## POST `/api/invitations`
4+
5+
Create and send an invitation to a new user.
6+
7+
**Request Body:**
8+
9+
```json
10+
{
11+
"email": "string",
12+
"firstName": "string",
13+
"lastName": "string",
14+
"role": "student | mentor | superAdmin",
15+
"projectId": "string (optional)"
16+
}
17+
```
18+
19+
**Success Response (201):**
20+
21+
```json
22+
{
23+
"message": "Invitation sent successfully",
24+
"invitation": {
25+
"id": "string",
26+
"email": "string",
27+
"role": "string",
28+
"token": "string",
29+
"createdAt": "ISO 8601",
30+
"expiresAt": "ISO 8601"
31+
}
32+
}
33+
```
34+
35+
**Authentication Required:** ✓ (superAdmin or mentor only)
36+
37+
---
38+
39+
## GET `/api/invitations?token=<token>`
40+
41+
Validate an invitation token.
42+
43+
**Query Parameters:**
44+
45+
- `token` (required) - Invitation token
46+
47+
**Success Response (200):**
48+
49+
```json
50+
{
51+
"valid": true,
52+
"invitation": {
53+
"id": "string",
54+
"email": "string",
55+
"role": "string",
56+
"token": "string",
57+
"createdAt": "ISO 8601",
58+
"expiresAt": "ISO 8601",
59+
"accepted": false
60+
}
61+
}
62+
```
63+
64+
---
65+
66+
## Frontend Hook: `useInvitation`
67+
68+
**Location:** `hooks/admin/useInvitation.ts`
69+
70+
```typescript
71+
import { useMutation, useQueryClient } from "@tanstack/react-query";
72+
import { toast } from "sonner";
73+
74+
interface InvitationRequest {
75+
email: string;
76+
firstName: string;
77+
lastName: string;
78+
role: "student" | "mentor" | "superAdmin";
79+
projectId?: string;
80+
}
81+
82+
interface InvitationResponse {
83+
message: string;
84+
invitation: {
85+
id: string;
86+
email: string;
87+
role: string;
88+
token: string;
89+
createdAt: string;
90+
expiresAt: string;
91+
};
92+
}
93+
94+
export const useInvitation = () => {
95+
const queryClient = useQueryClient();
96+
97+
const mutation = useMutation<InvitationResponse, Error, InvitationRequest>({
98+
mutationFn: async (data) => {
99+
const res = await fetch("/api/invitations", {
100+
method: "POST",
101+
headers: { "Content-Type": "application/json" },
102+
body: JSON.stringify(data),
103+
});
104+
105+
if (!res.ok) {
106+
const errorData = await res.json();
107+
throw new Error(errorData.message || "Failed to send invitation");
108+
}
109+
110+
return res.json();
111+
},
112+
onSuccess: () => {
113+
toast.success("Invitation sent successfully!");
114+
queryClient.invalidateQueries({ queryKey: ["invitations"] });
115+
},
116+
onError: (error) => {
117+
toast.error(error.message || "Failed to send invitation");
118+
},
119+
});
120+
121+
return mutation;
122+
};
123+
```
124+
125+
**Usage:**
126+
127+
```typescript
128+
const invitation = useInvitation();
129+
130+
await invitation.mutateAsync({
131+
email: "user@example.com",
132+
firstName: "John",
133+
lastName: "Doe",
134+
role: "student",
135+
});
136+
```

server/.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ AUDIENCE=http://localhost:3000
1919

2020
NEXT_PUBLIC_BASE_URL=http://localhost:3000
2121
# get the email pass key from https://myaccount.google.com/apppasswords
22-
EMAIL_USER= "ruchiralakshanm@gmail.com"
23-
EMAIL_PASS= "tocg pmis oowi cxdx"
22+
EMAIL_USER= ""
23+
EMAIL_PASS= ""

server/.prettierignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dist
2+
build
3+
node_modules
4+
routeTree.gen.ts

0 commit comments

Comments
 (0)