Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/blutui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from './exceptions'
import { Client } from './utils/client'

import { User } from './resources'
import { Agencies, User } from './resources'

import type {
BlutuiOptions,
Expand All @@ -30,6 +30,7 @@ export class Blutui {
private readonly client: Client
private readonly _agencies: Record<string, Agency> = {}

readonly agencies = new Agencies(this)
readonly user = new User(this)

/**
Expand Down
60 changes: 60 additions & 0 deletions src/resources/agencies/agencies.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import fetch from 'jest-fetch-mock'
import { Blutui } from '@/blutui'
import { fetchOnce, fetchURL } from '@/utils/testing'

import agencyFixture from './fixtures/agency.json'
import agencyListFixture from './fixtures/agency-list.json'

const accessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
const blutui = new Blutui(accessToken)

describe('Agency', () => {
beforeEach(() => fetch.resetMocks())

describe('list', () => {
it('can retrieve a list of agencies', async () => {
fetchOnce(agencyListFixture)
const agencies = await blutui.agencies.list()

expect(fetchURL()).toBe(`${blutui.baseURL}/v1/agencies`)
expect(agencies).toMatchObject({
object: 'list',
})
})
})

describe('get', () => {
it('can retrieve an agency', async () => {
fetchOnce(agencyFixture)
const agency = await blutui.agencies.get(agencyFixture.id)

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/${agencyFixture.id}`
)
expect(agency).toMatchObject({
id: '9af3accc-1536-4336-8cc3-3b3b2a96c18a',
object: 'agency',
isAgency: false,
})
})
})

describe('update', () => {
it('can update an agency', async () => {
fetchOnce(agencyFixture)
const agency = await blutui.agencies.update(agencyFixture.id, {
name: 'Foo',
})

expect(fetchURL()).toBe(
`${blutui.baseURL}/v1/agencies/${agencyFixture.id}`
)
expect(agency).toMatchObject({
id: '9af3accc-1536-4336-8cc3-3b3b2a96c18a',
object: 'agency',
isAwsCustomer: false,
})
})
})
})
51 changes: 51 additions & 0 deletions src/resources/agencies/agencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
deserializeAgency,
deserializeAgencyList,
serializeUpdateAgencyOptions,
} from './serializers'

import type { Blutui } from '@/blutui'
import type {
Agency,
AgencyResponse,
SerializedUpdateAgencyOptions,
UpdateAgencyOptions,
} from './interfaces'
import type { List, ListResponse, PaginationOptions } from '@/types'

export class Agencies {
constructor(private readonly blutui: Blutui) {}

/**
* Retrieve a list of agencies you belong to.
*/
async list(options?: PaginationOptions): Promise<List<Agency>> {
const { data } = await this.blutui.get<ListResponse<AgencyResponse>>(
'agencies',
{ query: options }
)

return deserializeAgencyList(data)
}

/**
* Get an agency you belong to, by ID.
*/
async get(id: string): Promise<Agency> {
const { data } = await this.blutui.get<AgencyResponse>(`agencies/${id}`)

return deserializeAgency(data)
}

/**
* Update an agency you belong to, by ID.
*/
async update(id: string, payload: UpdateAgencyOptions): Promise<Agency> {
const { data } = await this.blutui.patch<
AgencyResponse,
SerializedUpdateAgencyOptions
>(`agencies/${id}`, serializeUpdateAgencyOptions(payload))

return deserializeAgency(data)
}
}
31 changes: 31 additions & 0 deletions src/resources/agencies/fixtures/agency-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"object": "list",
"data": [
{
"id": "9af3accc-1536-4336-8cc3-3b3b2a96c18a",
"object": "agency",
"name": "Flume",
"email": "jayan@flume.agency",
"slug": "flume",
"url": "https://flume.agency",
"location": "NZ",
"timezone": "UTC",
"avatar": null,
"description": null,
"trial_mode": false,
"is_agency": false,
"is_aws_customer": false,
"created_at": 1703713667,
"updated_at": 1721087098
}
],
"meta": {
"hasMore": false,
"currentPage": 1,
"from": 1,
"to": 1,
"perPage": 10,
"total": 1,
"lastPage": 1
}
}
17 changes: 17 additions & 0 deletions src/resources/agencies/fixtures/agency.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"id": "9af3accc-1536-4336-8cc3-3b3b2a96c18a",
"object": "agency",
"name": "Flume",
"email": "jayan@flume.agency",
"slug": "flume",
"url": "https://flume.agency",
"location": "NZ",
"timezone": "UTC",
"avatar": null,
"description": null,
"trial_mode": false,
"is_agency": false,
"is_aws_customer": false,
"created_at": 1703713667,
"updated_at": 1721087098
}
37 changes: 37 additions & 0 deletions src/resources/agencies/interfaces/agency.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export interface Agency {
id: string
object: 'agency'
name: string
email: string
slug: string
url: string | null
location: string
timezone: string
avatar: string | null
description: string | null
trialMode: boolean
isAgency: boolean
isAwsCustomer: boolean
createdAt: number
updatedAt: number
deletedAt?: number
}

export interface AgencyResponse {
id: string
object: 'agency'
name: string
email: string
slug: string
url: string | null
location: string
timezone: string
avatar: string | null
description: string | null
trial_mode: boolean
is_agency: boolean
is_aws_customer: boolean
created_at: number
updated_at: number
deleted_at?: number
}
2 changes: 2 additions & 0 deletions src/resources/agencies/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './agency.interface'
export * from './update-agency-options.interface'
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface UpdateAgencyOptions {
name?: string
description?: string | null
email?: string
location?: string
url?: string | null
timezone?: string
avatar?: string | null
}

export interface SerializedUpdateAgencyOptions {
name?: string
description?: string | null
email?: string
location?: string
url?: string | null
timezone?: string
avatar?: string | null
}
31 changes: 31 additions & 0 deletions src/resources/agencies/serializers/agency.serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { deserializePaginationMeta } from '@/utils/serializers'

import type { List, ListResponse } from '@/types'
import type { Agency, AgencyResponse } from '../interfaces'

export const deserializeAgency = (agency: AgencyResponse): Agency => ({
id: agency.id,
object: agency.object,
name: agency.name,
email: agency.email,
slug: agency.slug,
url: agency.url,
location: agency.location,
timezone: agency.timezone,
avatar: agency.avatar,
description: agency.description,
trialMode: agency.trial_mode,
isAgency: agency.is_agency,
isAwsCustomer: agency.is_aws_customer,
createdAt: agency.created_at,
updatedAt: agency.updated_at,
deletedAt: agency.deleted_at,
})

export const deserializeAgencyList = (
agencies: ListResponse<AgencyResponse>
): List<Agency> => ({
object: agencies.object,
data: agencies.data.map(deserializeAgency),
meta: deserializePaginationMeta(agencies.meta),
})
2 changes: 2 additions & 0 deletions src/resources/agencies/serializers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './agency.serializer'
export * from './update-agency-options.serializer'
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type {
SerializedUpdateAgencyOptions,
UpdateAgencyOptions,
} from '../interfaces'

export const serializeUpdateAgencyOptions = (
options: UpdateAgencyOptions
): SerializedUpdateAgencyOptions => ({
name: options.name,
description: options.description,
email: options.email,
location: options.location,
url: options.url,
timezone: options.timezone,
avatar: options.avatar,
})
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const deserializeProject = (project: ProjectResponse): Project => ({
export const deserializeProjectList = (
projects: ListResponse<ProjectResponse>
): List<Project> => ({
object: 'list',
object: projects.object,
data: projects.data.map(deserializeProject),
meta: deserializePaginationMeta(projects.meta),
})
1 change: 1 addition & 0 deletions src/resources/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Agencies } from './agencies/agencies'
export { User } from './user/user'
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// Blutui Options

export interface BlutuiOptions {
apiHostname?: string
request?: {
fetch?: typeof fetch
}
}

// List
Expand Down