Skip to content

Commit b243235

Browse files
tomasciccolaTomás CiccolaEvanHahn
authored
feat: MemberInfo - expose when a project member joined the project (#745)
* add joinedAt to `MemberInfo`, expose it on `getByDocId` and `getMany` * fix tests * typo, spanish lurking Co-authored-by: Evan Hahn <[email protected]> --------- Co-authored-by: Tomás Ciccola <[email protected]> Co-authored-by: Evan Hahn <[email protected]>
1 parent 1fc0795 commit b243235

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

src/member-api.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { ROLES, isRoleIdForNewInvite } from './roles.js'
3030
* @prop {import('./roles.js').Role} role
3131
* @prop {import('@mapeo/schema').DeviceInfo['name']} [name]
3232
* @prop {import('@mapeo/schema').DeviceInfo['deviceType']} [deviceType]
33+
* @prop {import('@mapeo/schema').DeviceInfo['createdAt']} [joinedAt]
3334
*/
3435

3536
export class MemberApi extends TypedEmitter {
@@ -255,6 +256,7 @@ export class MemberApi extends TypedEmitter {
255256

256257
result.name = deviceInfo.name
257258
result.deviceType = deviceInfo.deviceType
259+
result.joinedAt = deviceInfo.createdAt
258260
} catch (err) {
259261
// Attempting to get someone else may throw because sync hasn't occurred or completed
260262
// Only throw if attempting to get themself since the relevant information should be available
@@ -290,6 +292,7 @@ export class MemberApi extends TypedEmitter {
290292

291293
memberInfo.name = deviceInfo?.name
292294
memberInfo.deviceType = deviceInfo?.deviceType
295+
memberInfo.joinedAt = deviceInfo?.createdAt
293296
} catch (err) {
294297
// Attempting to get someone else may throw because sync hasn't occurred or completed
295298
// Only throw if attempting to get themself since the relevant information should be available

test-e2e/members.js

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,16 @@ test('getting yourself after creating project', async (t) => {
2525
const deviceInfo = manager.getDeviceInfo()
2626
const project = await manager.getProject(await manager.createProject())
2727

28-
const me = await project.$member.getById(project.deviceId)
28+
const { joinedAt, ...me } = await project.$member.getById(project.deviceId)
29+
assert.ok(joinedAt, 'has a `joinedAt` field')
2930

31+
const joinedAtUnix = new Date(joinedAt).getTime()
32+
const now = new Date().getTime()
33+
34+
assert.ok(
35+
Math.abs(joinedAtUnix - now) < 1000,
36+
'time of joined project is close to now'
37+
)
3038
assert.deepEqual(
3139
me,
3240
{
@@ -39,10 +47,11 @@ test('getting yourself after creating project', async (t) => {
3947
)
4048

4149
const members = await project.$member.getMany()
50+
const { joinedAt: _, ...member } = members[0]
4251

4352
assert.equal(members.length, 1)
4453
assert.deepEqual(
45-
members[0],
54+
member,
4655
{
4756
deviceId: project.deviceId,
4857
deviceType: 'tablet',
@@ -68,7 +77,14 @@ test('getting yourself after adding project (but not yet synced)', async (t) =>
6877
)
6978
)
7079

71-
const me = await project.$member.getById(project.deviceId)
80+
const { joinedAt, ...me } = await project.$member.getById(project.deviceId)
81+
assert.ok(joinedAt, 'joinedAt exists at project')
82+
const joinedAtUnix = new Date(joinedAt).getTime()
83+
const now = new Date().getTime()
84+
assert.ok(
85+
Math.abs(now - joinedAtUnix) < 1000,
86+
'time between joined project and now is short'
87+
)
7288

7389
assert.deepEqual(
7490
me,
@@ -82,10 +98,11 @@ test('getting yourself after adding project (but not yet synced)', async (t) =>
8298
)
8399

84100
const members = await project.$member.getMany()
101+
const { joinedAt: _, ...member } = members[0]
85102

86103
assert.equal(members.length, 1)
87104
assert.deepEqual(
88-
members[0],
105+
member,
89106
{
90107
deviceId: project.deviceId,
91108
deviceType: 'tablet',
@@ -150,17 +167,27 @@ test('getting invited member after invite accepted', async (t) => {
150167
assert.equal(members.length, 2)
151168

152169
const invitedMember = members.find((m) => m.deviceId === invitee.deviceId)
170+
if (invitedMember) {
171+
const { joinedAt, ...invitedMemberWithoutJoinedAt } = invitedMember
172+
assert.ok(joinedAt, 'joinedAt exists for project')
173+
const joinedAtUnix = new Date(joinedAt).getTime()
174+
const now = new Date().getTime()
175+
assert.ok(
176+
Math.abs(now - joinedAtUnix) < 1000,
177+
'time between joined project and now is short'
178+
)
153179

154-
assert.deepEqual(
155-
invitedMember,
156-
{
157-
deviceId: invitee.deviceId,
158-
deviceType: undefined,
159-
name: inviteeName,
160-
role: ROLES[MEMBER_ROLE_ID],
161-
},
162-
'has expected member info with member role'
163-
)
180+
assert.deepEqual(
181+
invitedMemberWithoutJoinedAt,
182+
{
183+
deviceId: invitee.deviceId,
184+
deviceType: undefined,
185+
name: inviteeName,
186+
role: ROLES[MEMBER_ROLE_ID],
187+
},
188+
'has expected member info with member role'
189+
)
190+
}
164191

165192
// TODO: Test that device info of invited member can be read from invitor after syncing
166193
})

0 commit comments

Comments
 (0)