diff --git a/packages/plane-services/ai.service.ts b/packages/plane-services/ai.service.ts new file mode 100644 index 000000000..3b6772780 --- /dev/null +++ b/packages/plane-services/ai.service.ts @@ -0,0 +1,36 @@ +import APIService from "./api.service"; +import trackEventServices from "./track-event.service"; +// types +import { ICurrentUserResponse, IGptResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || + process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +export class AIServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createGptTask( + workspaceSlug: string, + projectId: string, + data: { prompt: string; task: string }, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/ai-assistant/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackAskGptEvent(response?.data, "ASK_GPT", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } +} diff --git a/packages/plane-services/analytics.service.ts b/packages/plane-services/analytics.service.ts new file mode 100644 index 000000000..f7aeffd41 --- /dev/null +++ b/packages/plane-services/analytics.service.ts @@ -0,0 +1,71 @@ +import APIService from "./api.service"; +// types +import { + IAnalyticsParams, + IAnalyticsResponse, + IDefaultAnalyticsResponse, + IExportAnalyticsFormData, + ISaveAnalyticsFormData, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +export class AnalyticsServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getAnalytics( + workspaceSlug: string, + params: IAnalyticsParams + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/analytics/`, { + params: { + ...params, + project: params?.project ? params.project.toString() : null, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getDefaultAnalytics( + workspaceSlug: string, + params?: Partial + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/default-analytics/`, { + params: { + ...params, + project: params?.project ? params.project.toString() : null, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async saveAnalytics( + workspaceSlug: string, + data: ISaveAnalyticsFormData + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/analytic-view/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async exportAnalytics( + workspaceSlug: string, + data: IExportAnalyticsFormData + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/export-analytics/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/plane-services/api.service.ts b/packages/plane-services/api.service.ts new file mode 100644 index 000000000..c71c75ba8 --- /dev/null +++ b/packages/plane-services/api.service.ts @@ -0,0 +1,156 @@ +import axios from "axios"; +import Cookies from "js-cookie"; + +const unAuthorizedStatus = [401]; +const nonValidatedRoutes = [ + "/", + "/magic-sign-in", + "/reset-password", + "/workspace-member-invitation", + "/sign-up", + "/m/", +]; + +const validateRouteCheck = (route: string): boolean => { + let validationToggle = false; + + let routeCheck = false; + nonValidatedRoutes.forEach((_route: string) => { + if (route.includes(_route)) { + routeCheck = true; + } + }); + + if (routeCheck) validationToggle = true; + return validationToggle; +}; + +axios.interceptors.response.use( + (response) => response, + (error) => { + const { status }: any = error.response; + if (!validateRouteCheck(window.location.pathname)) { + if (unAuthorizedStatus.includes(status)) { + Cookies.remove("refreshToken", { path: "/" }); + Cookies.remove("accessToken", { path: "/" }); + window.location.href = `/?next_url=${window.location.pathname}`; + } + } + return Promise.reject(error); + } +); + +abstract class APIService { + protected baseURL: string; + protected headers: any = {}; + + constructor(baseURL: string) { + this.baseURL = baseURL; + } + + setRefreshToken(token: string) { + Cookies.set("refreshToken", token); + } + + getRefreshToken() { + return Cookies.get("refreshToken"); + } + + purgeRefreshToken() { + Cookies.remove("refreshToken", { path: "/" }); + } + + setAccessToken(token: string) { + Cookies.set("accessToken", token); + } + + getAccessToken() { + return Cookies.get("accessToken"); + } + + purgeAccessToken() { + Cookies.remove("accessToken", { path: "/" }); + } + + getHeaders() { + return { + Authorization: `Bearer ${this.getAccessToken()}`, + }; + } + + getWithoutBase(url: string, config = {}): Promise { + return axios({ + method: "get", + url: url, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + get(url: string, config = {}): Promise { + return axios({ + method: "get", + url: this.baseURL + url, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + post(url: string, data = {}, config = {}): Promise { + return axios({ + method: "post", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + put(url: string, data = {}, config = {}): Promise { + return axios({ + method: "put", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + patch(url: string, data = {}, config = {}): Promise { + return axios({ + method: "patch", + url: this.baseURL + url, + data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + delete(url: string, data?: any, config = {}): Promise { + return axios({ + method: "delete", + url: this.baseURL + url, + data: data, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + + mediaUpload(url: string, data = {}, config = {}): Promise { + return axios({ + method: "post", + url: this.baseURL + url, + data, + headers: this.getAccessToken() + ? { ...this.getHeaders(), "Content-Type": "multipart/form-data" } + : {}, + ...config, + }); + } + + request(config = {}) { + return axios(config); + } +} + +export default APIService; diff --git a/packages/plane-services/app-installations.service.ts b/packages/plane-services/app-installations.service.ts new file mode 100644 index 000000000..dea6fa421 --- /dev/null +++ b/packages/plane-services/app-installations.service.ts @@ -0,0 +1,78 @@ +// services +import axios from "axios"; +import APIService from "services/api.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +class AppInstallationsService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async addInstallationApp(workspaceSlug: string, provider: string, data: any): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/workspace-integrations/${provider}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async addSlackChannel( + workspaceSlug: string, + projectId: string, + integrationId: string | null | undefined, + data: any + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getSlackChannelDetail( + workspaceSlug: string, + projectId: string, + integrationId: string | null | undefined + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async removeSlackChannel( + workspaceSlug: string, + projectId: string, + integrationId: string | null | undefined, + slackSyncId: string | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/project-slack-sync/${slackSyncId}` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getSlackAuthDetails(code: string): Promise { + const response = await axios({ + method: "post", + url: "/api/slack-redirect", + data: { + code, + }, + }); + + return response.data; + } +} + +export default new AppInstallationsService(); diff --git a/packages/plane-services/authentication.service.ts b/packages/plane-services/authentication.service.ts new file mode 100644 index 000000000..e4a33bff8 --- /dev/null +++ b/packages/plane-services/authentication.service.ts @@ -0,0 +1,85 @@ +// services +import APIService from "services/api.service"; +import { ICurrentUserResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +class AuthService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async emailLogin(data: any) { + return this.post("/api/sign-in/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async emailSignUp(data: { email: string; password: string }) { + return this.post("/api/sign-up/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async socialAuth(data: any): Promise<{ + access_token: string; + refresh_toke: string; + user: ICurrentUserResponse; + }> { + return this.post("/api/social-auth/", data, { headers: {} }) + .then((response) => { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async emailCode(data: any) { + return this.post("/api/magic-generate/", data, { headers: {} }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async magicSignIn(data: any) { + const response = await this.post("/api/magic-sign-in/", data, { headers: {} }); + if (response?.status === 200) { + this.setAccessToken(response?.data?.access_token); + this.setRefreshToken(response?.data?.refresh_token); + return response?.data; + } + throw response.response.data; + } + + async signOut() { + return this.post("/api/sign-out/", { refresh_token: this.getRefreshToken() }) + .then((response) => { + this.purgeAccessToken(); + this.purgeRefreshToken(); + return response?.data; + }) + .catch((error) => { + this.purgeAccessToken(); + this.purgeRefreshToken(); + throw error?.response?.data; + }); + } +} + +export default new AuthService(); diff --git a/packages/plane-services/csv.services.ts b/packages/plane-services/csv.services.ts new file mode 100644 index 000000000..f19cc4a74 --- /dev/null +++ b/packages/plane-services/csv.services.ts @@ -0,0 +1,42 @@ +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +import { ICurrentUserResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class CSVIntegrationService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async exportCSVService( + workspaceSlug: string, + data: { + provider: string; + project: string[]; + }, + user: ICurrentUserResponse + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/export-issues/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackExporterEvent( + { + workspaceSlug, + }, + "CSV_EXPORTER_CREATE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new CSVIntegrationService(); diff --git a/packages/plane-services/cycles.service.ts b/packages/plane-services/cycles.service.ts new file mode 100644 index 000000000..89cd50a2f --- /dev/null +++ b/packages/plane-services/cycles.service.ts @@ -0,0 +1,213 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +// types +import type { CycleDateCheckData, ICurrentUserResponse, ICycle, IIssue } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ProjectCycleServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createCycle( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getCyclesWithParams( + workspaceSlug: string, + projectId: string, + cycleType: "all" | "current" | "upcoming" | "draft" | "completed" | "incomplete" + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/`, { + params: { + cycle_view: cycleType, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getCycleDetails( + workspaceSlug: string, + projectId: string, + cycleId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`) + .then((res) => res?.data) + .catch((err) => { + throw err?.response?.data; + }); + } + + async getCycleIssues( + workspaceSlug: string, + projectId: string, + cycleId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getCycleIssuesWithParams( + workspaceSlug: string, + projectId: string, + cycleId: string, + queries?: any + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, + { params: queries } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.put( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackCycleEvent(response?.data, "CYCLE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async cycleDateCheck( + workspaceSlug: string, + projectId: string, + data: CycleDateCheckData + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/date-check/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addCycleToFavorites( + workspaceSlug: string, + projectId: string, + data: { + cycle: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async transferIssues( + workspaceSlug: string, + projectId: string, + cycleId: string, + data: { + new_cycle_id: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/transfer-issues/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeCycleFromFavorites( + workspaceSlug: string, + projectId: string, + cycleId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/${cycleId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ProjectCycleServices(); diff --git a/packages/plane-services/estimates.service.ts b/packages/plane-services/estimates.service.ts new file mode 100644 index 000000000..8b0fe25f4 --- /dev/null +++ b/packages/plane-services/estimates.service.ts @@ -0,0 +1,97 @@ +// services +import APIService from "services/api.service"; +// types +import type { ICurrentUserResponse, IEstimate, IEstimateFormData } from "types"; +import trackEventServices from "services/track-event.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ProjectEstimateServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createEstimate( + workspaceSlug: string, + projectId: string, + data: IEstimateFormData, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async patchEstimate( + workspaceSlug: string, + projectId: string, + estimateId: string, + data: IEstimateFormData, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getEstimateDetails( + workspaceSlug: string, + projectId: string, + estimateId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getEstimatesList(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteEstimate( + workspaceSlug: string, + projectId: string, + estimateId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/estimates/${estimateId}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueEstimateEvent(response?.data, "ESTIMATE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ProjectEstimateServices(); diff --git a/packages/plane-services/file.service.ts b/packages/plane-services/file.service.ts new file mode 100644 index 000000000..d2f01428d --- /dev/null +++ b/packages/plane-services/file.service.ts @@ -0,0 +1,99 @@ +// services +import APIService from "services/api.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +interface UnSplashImage { + id: string; + created_at: Date; + updated_at: Date; + promoted_at: Date; + width: number; + height: number; + color: string; + blur_hash: string; + description: null; + alt_description: string; + urls: UnSplashImageUrls; + [key: string]: any; +} + +interface UnSplashImageUrls { + raw: string; + full: string; + regular: string; + small: string; + thumb: string; + small_s3: string; +} + +class FileServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async uploadFile(workspaceSlug: string, file: FormData): Promise { + return this.mediaUpload(`/api/workspaces/${workspaceSlug}/file-assets/`, file) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteImage(assetUrlWithWorkspaceId: string): Promise { + return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`) + .then((response) => response?.status) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteFile(workspaceId: string, assetUrl: string): Promise { + const lastIndex = assetUrl.lastIndexOf("/"); + const assetId = assetUrl.substring(lastIndex + 1); + + return this.delete(`/api/workspaces/file-assets/${workspaceId}/${assetId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + async uploadUserFile(file: FormData): Promise { + return this.mediaUpload(`/api/users/file-assets/`, file) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteUserFile(assetUrl: string): Promise { + const lastIndex = assetUrl.lastIndexOf("/"); + const assetId = assetUrl.substring(lastIndex + 1); + + return this.delete(`/api/users/file-assets/${assetId}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUnsplashImages(page: number = 1, query?: string): Promise { + const url = "/api/unsplash"; + + return this.request({ + method: "get", + url, + params: { + page, + per_page: 20, + query, + }, + }) + .then((response) => response?.data?.results ?? response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new FileServices(); diff --git a/packages/plane-services/github.service.ts b/packages/plane-services/github.service.ts new file mode 100644 index 000000000..494785f04 --- /dev/null +++ b/packages/plane-services/github.service.ts @@ -0,0 +1,60 @@ +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +import { ICurrentUserResponse, IGithubRepoInfo, IGithubServiceImportFormData } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +const integrationServiceType: string = "github"; +class GithubIntegrationService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async listAllRepositories(workspaceSlug: string, integrationSlug: string): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/workspace-integrations/${integrationSlug}/github-repositories` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getGithubRepoInfo( + workspaceSlug: string, + params: { owner: string; repo: string } + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/importers/${integrationServiceType}/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createGithubServiceImport( + workspaceSlug: string, + data: IGithubServiceImportFormData, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/importers/${integrationServiceType}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackImporterEvent(response?.data, "GITHUB_IMPORTER_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new GithubIntegrationService(); diff --git a/packages/plane-services/inbox.service.ts b/packages/plane-services/inbox.service.ts new file mode 100644 index 000000000..61949c877 --- /dev/null +++ b/packages/plane-services/inbox.service.ts @@ -0,0 +1,183 @@ +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +// types +import type { + IInboxIssue, + IInbox, + TInboxStatus, + IInboxIssueDetail, + ICurrentUserResponse, + IInboxFilterOptions, + IInboxQueryParams, +} from "types"; + +class InboxServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getInboxes(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxById(workspaceSlug: string, projectId: string, inboxId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchInbox( + workspaceSlug: string, + projectId: string, + inboxId: string, + data: Partial + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxIssues( + workspaceSlug: string, + projectId: string, + inboxId: string, + params?: IInboxQueryParams + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, + { params } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getInboxIssueById( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markInboxStatus( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: TInboxStatus, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, + data + ) + .then((response) => { + const action = + data.status === -1 + ? "INBOX_ISSUE_REJECTED" + : data.status === 0 + ? "INBOX_ISSUE_SNOOZED" + : data.status === 1 + ? "INBOX_ISSUE_ACCEPTED" + : "INBOX_ISSUE_DUPLICATED"; + if (trackEvent) trackEventServices.trackInboxEvent(response?.data, action, user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + inboxIssueId: string, + data: { issue: Partial }, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/${inboxIssueId}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createInboxIssue( + workspaceSlug: string, + projectId: string, + inboxId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/inboxes/${inboxId}/inbox-issues/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackInboxEvent(response?.data, "INBOX_ISSUE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +const inboxServices = new InboxServices(); + +export default inboxServices; diff --git a/packages/plane-services/index.ts b/packages/plane-services/index.ts new file mode 100644 index 000000000..42151f0b8 --- /dev/null +++ b/packages/plane-services/index.ts @@ -0,0 +1 @@ +export \ No newline at end of file diff --git a/packages/plane-services/integration.service.ts b/packages/plane-services/integration.service.ts new file mode 100644 index 000000000..ac6e5ac4f --- /dev/null +++ b/packages/plane-services/integration.service.ts @@ -0,0 +1,107 @@ +import APIService from "./api.service"; +import trackEventServices from "./track-event.service"; +// types +import { + IAppIntegration, + ICurrentUserResponse, + IImporterService, + IWorkspaceIntegration, + IExportServiceResponse, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || + process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class IntegrationService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getAppIntegrationsList(): Promise { + return this.get(`/api/integrations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceIntegrationsList( + workspaceSlug: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/workspace-integrations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteWorkspaceIntegration( + workspaceSlug: string, + integrationId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/workspace-integrations/${integrationId}/provider/` + ) + .then((res) => res?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getImporterServicesList( + workspaceSlug: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/importers/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + async getExportsServicesList( + workspaceSlug: string, + cursor: string, + per_page: number + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/export-issues`, { + params: { + per_page, + cursor, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteImporterService( + workspaceSlug: string, + service: string, + importerId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/importers/${service}/${importerId}/` + ) + .then((response) => { + const eventName = + service === "github" + ? "GITHUB_IMPORTER_DELETE" + : "JIRA_IMPORTER_DELETE"; + + if (trackEvent) + trackEventServices.trackImporterEvent( + response?.data, + eventName, + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} diff --git a/packages/plane-services/issues.service.ts b/packages/plane-services/issues.service.ts new file mode 100644 index 000000000..8362ab261 --- /dev/null +++ b/packages/plane-services/issues.service.ts @@ -0,0 +1,589 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; +// type +import type { + ICurrentUserResponse, + IIssue, + IIssueActivity, + IIssueComment, + IIssueLabels, + ISubIssueResponse, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ProjectIssuesServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createIssues( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssues(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssuesWithParams( + workspaceSlug: string, + projectId: string, + queries?: any + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieve(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueActivities( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/history/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueComments(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueProperties(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addIssueToCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + data: { + issues: string[]; + }, + user: ICurrentUserResponse | undefined + ) { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueMovedToCycleOrModuleEvent( + { + workspaceSlug, + workspaceName: response?.data?.[0]?.issue_detail?.workspace_detail?.name, + projectId, + projectIdentifier: response?.data?.[0]?.issue_detail?.project_detail?.identifier, + projectName: response?.data?.[0]?.issue_detail?.project_detail?.name, + issueId: response?.data?.[0]?.issue_detail?.id, + cycleId, + }, + response.data.length > 1 ? "ISSUE_MOVED_TO_CYCLE_IN_BULK" : "ISSUE_MOVED_TO_CYCLE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeIssueFromCycle( + workspaceSlug: string, + projectId: string, + cycleId: string, + bridgeId: string + ) { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/${bridgeId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueProperties(workspaceSlug: string, projectId: string, data: any): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchIssueProperties( + workspaceSlug: string, + projectId: string, + issuePropertyId: string, + data: any + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` + + `${issuePropertyId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueComment( + workspaceSlug: string, + projectId: string, + issueId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchIssueComment( + workspaceSlug: string, + projectId: string, + issueId: string, + commentId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/${commentId}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueComment( + workspaceSlug: string, + projectId: string, + issueId: string, + commentId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/${commentId}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueCommentEvent( + { + issueId, + commentId, + }, + "ISSUE_COMMENT_DELETE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceLabels(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/labels/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueLabels(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueLabel( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/`, data) + .then((response: { data: IIssueLabels; [key: string]: any }) => { + if (trackEvent) + trackEventServices.trackIssueLabelEvent( + { + workSpaceId: response?.data?.workspace_detail?.id, + workSpaceName: response?.data?.workspace_detail?.name, + workspaceSlug, + projectId, + projectIdentifier: response?.data?.project_detail?.identifier, + projectName: response?.data?.project_detail?.name, + labelId: response?.data?.id, + color: response?.data?.color, + }, + "ISSUE_LABEL_CREATE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchIssueLabel( + workspaceSlug: string, + projectId: string, + labelId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueLabelEvent( + { + workSpaceId: response?.data?.workspace_detail?.id, + workSpaceName: response?.data?.workspace_detail?.name, + workspaceSlug, + projectId, + projectIdentifier: response?.data?.project_detail?.identifier, + projectName: response?.data?.project_detail?.name, + labelId: response?.data?.id, + color: response?.data?.color, + }, + "ISSUE_LABEL_UPDATE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueLabel( + workspaceSlug: string, + projectId: string, + labelId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueLabelEvent( + { + workspaceSlug, + projectId, + }, + "ISSUE_LABEL_DELETE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchIssue( + workspaceSlug: string, + projectId: string, + issueId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssue( + workspaceSlug: string, + projectId: string, + issuesId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issuesId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackIssueEvent({ issuesId }, "ISSUE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async bulkDeleteIssues( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackIssueBulkDeleteEvent(data, user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async subIssues( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addSubIssues( + workspaceSlug: string, + projectId: string, + issueId: string, + data: { sub_issue_ids: string[] } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueLink( + workspaceSlug: string, + projectId: string, + issueId: string, + data: { + metadata: any; + title: string; + url: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateIssueLink( + workspaceSlug: string, + projectId: string, + issueId: string, + linkId: string, + data: { + metadata: any; + title: string; + url: string; + } + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async deleteIssueLink( + workspaceSlug: string, + projectId: string, + issueId: string, + linkId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async uploadIssueAttachment( + workspaceSlug: string, + projectId: string, + issueId: string, + file: FormData + ): Promise { + return this.mediaUpload( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/`, + file + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueAttachment( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueAttachment( + workspaceSlug: string, + projectId: string, + issueId: string, + assetId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/${assetId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getArchivedIssues(workspaceSlug: string, projectId: string, queries?: any): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/`, { + params: queries, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async unarchiveIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/unarchive/${issueId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async retrieveArchivedIssue( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issueId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteArchivedIssue( + workspaceSlug: string, + projectId: string, + issuesId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issuesId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ProjectIssuesServices(); diff --git a/packages/plane-services/jira.service.ts b/packages/plane-services/jira.service.ts new file mode 100644 index 000000000..8f6a9fec9 --- /dev/null +++ b/packages/plane-services/jira.service.ts @@ -0,0 +1,46 @@ +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +// types +import { IJiraMetadata, IJiraResponse, IJiraImporterForm, ICurrentUserResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class JiraImportedService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getJiraProjectInfo(workspaceSlug: string, params: IJiraMetadata): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/importers/jira`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createJiraImporter( + workspaceSlug: string, + data: IJiraImporterForm, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/importers/jira/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackImporterEvent(response?.data, "JIRA_IMPORTER_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +const jiraImporterService = new JiraImportedService(); + +export default jiraImporterService; diff --git a/packages/plane-services/modules.service.ts b/packages/plane-services/modules.service.ts new file mode 100644 index 000000000..898164366 --- /dev/null +++ b/packages/plane-services/modules.service.ts @@ -0,0 +1,283 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "./track-event.service"; + +// types +import type { IModule, IIssue, ICurrentUserResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ProjectIssuesServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getModules(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createModule( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.put( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getModuleDetails( + workspaceSlug: string, + projectId: string, + moduleId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/` + ) + .then((response) => { + if (trackEvent) trackEventServices.trackModuleEvent(response?.data, "MODULE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getModuleIssues( + workspaceSlug: string, + projectId: string, + moduleId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-issues/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getModuleIssuesWithParams( + workspaceSlug: string, + projectId: string, + moduleId: string, + queries?: any + ): Promise< + | IIssue[] + | { + [key: string]: IIssue[]; + } + > { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-issues/`, + { params: queries } + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addIssuesToModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: { issues: string[] }, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-issues/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackIssueMovedToCycleOrModuleEvent( + { + workspaceSlug, + workspaceName: response?.data?.[0]?.issue_detail?.workspace_detail?.name, + projectId, + projectIdentifier: response?.data?.[0]?.issue_detail?.project_detail?.identifier, + projectName: response?.data?.[0]?.issue_detail?.project_detail?.name, + issueId: response?.data?.[0]?.issue_detail?.id, + moduleId, + }, + response?.data?.length > 1 ? "ISSUE_MOVED_TO_MODULE_IN_BULK" : "ISSUE_MOVED_TO_MODULE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeIssueFromModule( + workspaceSlug: string, + projectId: string, + moduleId: string, + bridgeId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-issues/${bridgeId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createModuleLink( + workspaceSlug: string, + projectId: string, + moduleId: string, + data: { + metadata: any; + title: string; + url: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateModuleLink( + workspaceSlug: string, + projectId: string, + moduleId: string, + linkId: string, + data: { + metadata: any; + title: string; + url: string; + } + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async deleteModuleLink( + workspaceSlug: string, + projectId: string, + moduleId: string, + linkId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addModuleToFavorites( + workspaceSlug: string, + projectId: string, + data: { + module: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeModuleFromFavorites( + workspaceSlug: string, + projectId: string, + moduleId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/${moduleId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ProjectIssuesServices(); diff --git a/packages/plane-services/notifications.service.ts b/packages/plane-services/notifications.service.ts new file mode 100644 index 000000000..01c139b51 --- /dev/null +++ b/packages/plane-services/notifications.service.ts @@ -0,0 +1,193 @@ +// services +import APIService from "services/api.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +// types +import type { + IUserNotification, + INotificationParams, + NotificationCount, + PaginatedUserNotification, + IMarkAllAsReadPayload, +} from "types"; + +class UserNotificationsServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getUserNotifications( + workspaceSlug: string, + params: INotificationParams + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserNotificationDetailById( + workspaceSlug: string, + notificationId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsRead( + workspaceSlug: string, + notificationId: string + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsUnread( + workspaceSlug: string, + notificationId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/read/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsArchived( + workspaceSlug: string, + notificationId: string + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markUserNotificationAsUnarchived( + workspaceSlug: string, + notificationId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/archive/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchUserNotification( + workspaceSlug: string, + notificationId: string, + data: Partial + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteUserNotification(workspaceSlug: string, notificationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/users/notifications/${notificationId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async subscribeToIssueNotifications( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssueNotificationSubscriptionStatus( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise<{ + subscribed: boolean; + }> { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async unsubscribeFromIssueNotifications( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/subscribe/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUnreadNotificationsCount(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/users/notifications/unread/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getNotifications(url: string): Promise { + return this.get(url) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async markAllNotificationsAsRead( + workspaceSlug: string, + payload: IMarkAllAsReadPayload + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/users/notifications/mark-all-read/`, { + ...payload, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +const userNotificationServices = new UserNotificationsServices(); + +export default userNotificationServices; diff --git a/packages/plane-services/package.json b/packages/plane-services/package.json new file mode 100644 index 000000000..359313ab1 --- /dev/null +++ b/packages/plane-services/package.json @@ -0,0 +1,15 @@ +{ + "name": "plane-services", + "version": "0.0.1", + "main": "index.ts", + "license": "MIT", + "dependencies": { + "axios": "^1.5.0" + }, + "devDependencies": { + "typescript": "^4.7.4" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/plane-services/pages.service.ts b/packages/plane-services/pages.service.ts new file mode 100644 index 000000000..72b12012e --- /dev/null +++ b/packages/plane-services/pages.service.ts @@ -0,0 +1,250 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +// types +import { IPage, IPageBlock, RecentPagesResponse, IIssue, ICurrentUserResponse } from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class PageServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createPage( + workspaceSlug: string, + projectId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchPage( + workspaceSlug: string, + projectId: string, + pageId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deletePage( + workspaceSlug: string, + projectId: string, + pageId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackPageEvent(response?.data, "PAGE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addPageToFavorites( + workspaceSlug: string, + projectId: string, + data: { + page: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-pages/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removePageFromFavorites(workspaceSlug: string, projectId: string, pageId: string) { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-pages/${pageId}` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPagesWithParams( + workspaceSlug: string, + projectId: string, + pageType: "all" | "favorite" | "created_by_me" | "created_by_other" + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, { + params: { + page_view: pageType, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getRecentPages(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`, { + params: { + page_view: "recent", + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPageDetails(workspaceSlug: string, projectId: string, pageId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + pageBlockId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchPageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + pageBlockId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deletePageBlock( + workspaceSlug: string, + projectId: string, + pageId: string, + pageBlockId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${pageBlockId}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackPageBlockEvent(response?.data, "PAGE_BLOCK_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async listPageBlocks( + workspaceSlug: string, + projectId: string, + pageId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async convertPageBlockToIssue( + workspaceSlug: string, + projectId: string, + pageId: string, + blockId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/${pageId}/page-blocks/${blockId}/issues/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackPageBlockEvent( + response?.data, + "PAGE_BLOCK_CONVERTED_TO_ISSUE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new PageServices(); diff --git a/packages/plane-services/project-publish.service.ts b/packages/plane-services/project-publish.service.ts new file mode 100644 index 000000000..4ee01a94b --- /dev/null +++ b/packages/plane-services/project-publish.service.ts @@ -0,0 +1,117 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; +// types +import { ICurrentUserResponse } from "types"; +import { IProjectPublishSettings } from "store/project-publish"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ProjectServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async getProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.get( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/` + ) + .then((response) => { + if (trackEvent) { + // trackEventServices.trackProjectPublishSettingsEvent( + // response.data, + // "GET_PROJECT_PUBLISH_SETTINGS", + // user + // ); + } + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async createProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + data: IProjectPublishSettings, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/`, + data + ) + .then((response) => { + if (trackEvent) { + // trackEventServices.trackProjectPublishSettingsEvent( + // response.data, + // "CREATE_PROJECT_PUBLISH_SETTINGS", + // user + // ); + } + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async updateProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + project_publish_id: string, + data: IProjectPublishSettings, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/`, + data + ) + .then((response) => { + if (trackEvent) { + // trackEventServices.trackProjectPublishSettingsEvent( + // response.data, + // "UPDATE_PROJECT_PUBLISH_SETTINGS", + // user + // ); + } + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async deleteProjectSettingsAsync( + workspace_slug: string, + project_slug: string, + project_publish_id: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete( + `/api/workspaces/${workspace_slug}/projects/${project_slug}/project-deploy-boards/${project_publish_id}/` + ) + .then((response) => { + if (trackEvent) { + // trackEventServices.trackProjectPublishSettingsEvent( + // response.data, + // "DELETE_PROJECT_PUBLISH_SETTINGS", + // user + // ); + } + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } +} + +export default ProjectServices; diff --git a/packages/plane-services/project.service.ts b/packages/plane-services/project.service.ts new file mode 100644 index 000000000..0d97b9efb --- /dev/null +++ b/packages/plane-services/project.service.ts @@ -0,0 +1,392 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +// types +import type { + GithubRepositoriesResponse, + ICurrentUserResponse, + IProject, + IProjectBulkInviteFormData, + IProjectMember, + IProjectMemberInvitation, + ISearchIssueResponse, + ProjectPreferences, + IProjectViewProps, + TProjectIssuesSearchParams, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +export class ProjectServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createProject( + workspaceSlug: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "CREATE_PROJECT", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async checkProjectIdentifierAvailability(workspaceSlug: string, data: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/project-identifiers`, { + params: { + name: data, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProjects( + workspaceSlug: string, + params: { + is_favorite: "all" | boolean; + } + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProject(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateProject( + workspaceSlug: string, + projectId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackProjectEvent(response.data, "UPDATE_PROJECT", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteProject( + workspaceSlug: string, + projectId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async inviteProject( + workspaceSlug: string, + projectId: string, + data: IProjectBulkInviteFormData, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/add/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackProjectEvent( + { + workspaceId: response?.data?.workspace?.id, + workspaceSlug, + projectId, + projectName: response?.data?.project?.name, + memberEmail: response?.data?.member?.email, + }, + "PROJECT_MEMBER_INVITE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async joinProject(workspaceSlug: string, data: any): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/join/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async leaveProject( + workspaceSlug: string, + projectId: string, + user: ICurrentUserResponse + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/leave/`) + .then((response) => { + if (trackEvent) + trackEventServices.trackProjectEvent( + "PROJECT_MEMBER_LEAVE", + { + workspaceSlug, + projectId, + ...response?.data, + }, + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async joinProjects(data: any): Promise { + return this.post("/api/users/me/invitations/projects/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectMembers(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectMembersWithEmail( + workspaceSlug: string, + projectId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectMemberMe(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/me/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async getProjectMember( + workspaceSlug: string, + projectId: string, + memberId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateProjectMember( + workspaceSlug: string, + projectId: string, + memberId: string, + data: Partial + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteProjectMember( + workspaceSlug: string, + projectId: string, + memberId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectInvitations( + workspaceSlug: string, + projectId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectInvitationsWithEmail( + workspaceSlug: string, + projectId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateProjectInvitation( + workspaceSlug: string, + projectId: string, + invitationId: string + ): Promise { + return this.put( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteProjectInvitation( + workspaceSlug: string, + projectId: string, + invitationId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async setProjectView( + workspaceSlug: string, + projectId: string, + data: { + view_props?: IProjectViewProps; + default_props?: IProjectViewProps; + preferences?: ProjectPreferences; + sort_order?: number; + } + ): Promise { + await this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-views/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getGithubRepositories(url: string): Promise { + return this.getWithoutBase(url) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async syncGithubRepository( + workspaceSlug: string, + projectId: string, + workspaceIntegrationId: string, + data: { + name: string; + owner: string; + repository_id: string; + url: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${workspaceIntegrationId}/github-repository-sync/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getProjectGithubRepository( + workspaceSlug: string, + projectId: string, + integrationId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/github-repository-sync/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addProjectToFavorites( + workspaceSlug: string, + data: { + project: string; + } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/user-favorite-projects/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeProjectFromFavorites(workspaceSlug: string, projectId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/user-favorite-projects/${projectId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async projectIssuesSearch( + workspaceSlug: string, + projectId: string, + params: TProjectIssuesSearchParams + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/search-issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ProjectServices(); diff --git a/packages/plane-services/reaction.service.ts b/packages/plane-services/reaction.service.ts new file mode 100644 index 000000000..3ba8a83e4 --- /dev/null +++ b/packages/plane-services/reaction.service.ts @@ -0,0 +1,145 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +// types +import type { + ICurrentUserResponse, + IssueReaction, + IssueCommentReaction, + IssueReactionForm, + IssueCommentReactionForm, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ReactionService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createIssueReaction( + workspaceSlug: string, + projectId: string, + issueId: string, + data: IssueReactionForm, + user?: ICurrentUserResponse + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackReactionEvent(response?.data, "ISSUE_REACTION_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async listIssueReactions( + workspaceSlug: string, + projectId: string, + issueId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueReaction( + workspaceSlug: string, + projectId: string, + issueId: string, + reaction: string, + user?: ICurrentUserResponse + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/reactions/${reaction}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackReactionEvent(response?.data, "ISSUE_REACTION_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async createIssueCommentReaction( + workspaceSlug: string, + projectId: string, + commentId: string, + data: IssueCommentReactionForm, + user?: ICurrentUserResponse + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/`, + data + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackReactionEvent( + response?.data, + "ISSUE_COMMENT_REACTION_CREATE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async listIssueCommentReactions( + workspaceSlug: string, + projectId: string, + commentId: string + ): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteIssueCommentReaction( + workspaceSlug: string, + projectId: string, + commentId: string, + reaction: string, + user?: ICurrentUserResponse + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/comments/${commentId}/reactions/${reaction}/` + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackReactionEvent( + response?.data, + "ISSUE_COMMENT_REACTION_DELETE", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +const reactionService = new ReactionService(); + +export default reactionService; diff --git a/packages/plane-services/state.service.ts b/packages/plane-services/state.service.ts new file mode 100644 index 000000000..52481f8bb --- /dev/null +++ b/packages/plane-services/state.service.ts @@ -0,0 +1,116 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +// types +import type { ICurrentUserResponse, IState, IStateResponse } from "types"; + +class ProjectStateServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createState( + workspaceSlug: string, + projectId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async getStates(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getIssuesByState(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/?group_by=state`) + + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getState(workspaceSlug: string, projectId: string, stateId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateState( + workspaceSlug: string, + projectId: string, + stateId: string, + data: IState, + user: ICurrentUserResponse | undefined + ): Promise { + return this.put( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } + + async patchState( + workspaceSlug: string, + projectId: string, + stateId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteState( + workspaceSlug: string, + projectId: string, + stateId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/${stateId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackStateEvent(response?.data, "STATE_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response; + }); + } +} + +export default new ProjectStateServices(); diff --git a/packages/plane-services/track-event.service.ts b/packages/plane-services/track-event.service.ts new file mode 100644 index 000000000..c59242f50 --- /dev/null +++ b/packages/plane-services/track-event.service.ts @@ -0,0 +1,889 @@ +// services +import APIService from "services/api.service"; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +// types +import type { + ICurrentUserResponse, + ICycle, + IEstimate, + IGptResponse, + IIssue, + IIssueComment, + IModule, + IPage, + IPageBlock, + IProject, + IState, + IView, + IWorkspace, + IssueCommentReaction, + IssueReaction, +} from "types"; + +type WorkspaceEventType = + | "CREATE_WORKSPACE" + | "UPDATE_WORKSPACE" + | "DELETE_WORKSPACE" + | "WORKSPACE_USER_INVITE" + | "WORKSPACE_USER_INVITE_ACCEPT" + | "WORKSPACE_USER_BULK_INVITE_ACCEPT"; + +type ProjectEventType = + | "CREATE_PROJECT" + | "UPDATE_PROJECT" + | "DELETE_PROJECT" + | "PROJECT_MEMBER_INVITE" + | "PROJECT_MEMBER_LEAVE"; + +type IssueEventType = "ISSUE_CREATE" | "ISSUE_UPDATE" | "ISSUE_DELETE"; + +type CycleEventType = "CYCLE_CREATE" | "CYCLE_UPDATE" | "CYCLE_DELETE"; + +type StateEventType = "STATE_CREATE" | "STATE_UPDATE" | "STATE_DELETE"; + +type ModuleEventType = "MODULE_CREATE" | "MODULE_UPDATE" | "MODULE_DELETE"; + +type PagesEventType = "PAGE_CREATE" | "PAGE_UPDATE" | "PAGE_DELETE"; + +type ViewEventType = "VIEW_CREATE" | "VIEW_UPDATE" | "VIEW_DELETE"; + +type IssueCommentEventType = + | "ISSUE_COMMENT_CREATE" + | "ISSUE_COMMENT_UPDATE" + | "ISSUE_COMMENT_DELETE"; + +type Toggle = + | "TOGGLE_CYCLE" + | "TOGGLE_MODULE" + | "TOGGLE_VIEW" + | "TOGGLE_PAGES" + | "TOGGLE_STATE" + | "TOGGLE_INBOX"; + +export type MiscellaneousEventType = `${Toggle}_ON` | `${Toggle}_OFF`; + +type IntegrationEventType = "ADD_WORKSPACE_INTEGRATION" | "REMOVE_WORKSPACE_INTEGRATION"; + +type GitHubSyncEventType = "GITHUB_REPO_SYNC"; + +type PageBlocksEventType = + | "PAGE_BLOCK_CREATE" + | "PAGE_BLOCK_UPDATE" + | "PAGE_BLOCK_DELETE" + | "PAGE_BLOCK_CONVERTED_TO_ISSUE"; + +type IssueLabelEventType = "ISSUE_LABEL_CREATE" | "ISSUE_LABEL_UPDATE" | "ISSUE_LABEL_DELETE"; + +type GptEventType = "ASK_GPT" | "USE_GPT_RESPONSE_IN_ISSUE" | "USE_GPT_RESPONSE_IN_PAGE_BLOCK"; + +type IssueEstimateEventType = "ESTIMATE_CREATE" | "ESTIMATE_UPDATE" | "ESTIMATE_DELETE"; + +type InboxEventType = + | "INBOX_CREATE" + | "INBOX_UPDATE" + | "INBOX_DELETE" + | "INBOX_ISSUE_CREATE" + | "INBOX_ISSUE_UPDATE" + | "INBOX_ISSUE_DELETE" + | "INBOX_ISSUE_DUPLICATED" + | "INBOX_ISSUE_ACCEPTED" + | "INBOX_ISSUE_SNOOZED" + | "INBOX_ISSUE_REJECTED"; + +type ImporterEventType = + | "GITHUB_IMPORTER_CREATE" + | "GITHUB_IMPORTER_DELETE" + | "JIRA_IMPORTER_CREATE" + | "JIRA_IMPORTER_DELETE"; + +type ExporterEventType = "CSV_EXPORTER_CREATE"; + +type AnalyticsEventType = + | "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" + | "WORKSPACE_CUSTOM_ANALYTICS" + | "WORKSPACE_ANALYTICS_EXPORT" + | "PROJECT_SCOPE_AND_DEMAND_ANALYTICS" + | "PROJECT_CUSTOM_ANALYTICS" + | "PROJECT_ANALYTICS_EXPORT" + | "CYCLE_SCOPE_AND_DEMAND_ANALYTICS" + | "CYCLE_CUSTOM_ANALYTICS" + | "CYCLE_ANALYTICS_EXPORT" + | "MODULE_SCOPE_AND_DEMAND_ANALYTICS" + | "MODULE_CUSTOM_ANALYTICS" + | "MODULE_ANALYTICS_EXPORT"; + +type ReactionEventType = + | "ISSUE_REACTION_CREATE" + | "ISSUE_COMMENT_REACTION_CREATE" + | "ISSUE_REACTION_DELETE" + | "ISSUE_COMMENT_REACTION_DELETE"; + +class TrackEventServices extends APIService { + constructor() { + super("/"); + } + + async trackWorkspaceEvent( + data: IWorkspace | any, + eventName: WorkspaceEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if ( + eventName !== "DELETE_WORKSPACE" && + eventName !== "WORKSPACE_USER_INVITE" && + eventName !== "WORKSPACE_USER_INVITE_ACCEPT" && + eventName !== "WORKSPACE_USER_BULK_INVITE_ACCEPT" + ) + payload = { + workspaceId: data.id, + workspaceSlug: data.slug, + workspaceName: data.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackProjectEvent( + data: Partial | any, + eventName: ProjectEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if ( + eventName !== "DELETE_PROJECT" && + eventName !== "PROJECT_MEMBER_INVITE" && + eventName !== "PROJECT_MEMBER_LEAVE" + ) + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.id, + projectName: data?.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackUserOnboardingCompleteEvent( + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName: "USER_ONBOARDING_COMPLETE", + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackUserTourCompleteEvent( + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName: "USER_TOUR_COMPLETE", + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssueEvent( + data: IIssue | any, + eventName: IssueEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "ISSUE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + issueId: data?.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackIssueMarkedAsDoneEvent( + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + if (!trackEvent) return; + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName: "ISSUES_MARKED_AS_DONE", + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssuePartialPropertyUpdateEvent( + data: any, + propertyName: + | "ISSUE_PROPERTY_UPDATE_PRIORITY" + | "ISSUE_PROPERTY_UPDATE_STATE" + | "ISSUE_PROPERTY_UPDATE_ASSIGNEE" + | "ISSUE_PROPERTY_UPDATE_DUE_DATE" + | "ISSUE_PROPERTY_UPDATE_ESTIMATE", + user: ICurrentUserResponse | undefined + ): Promise { + if (!trackEvent) return; + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName: propertyName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssueCommentEvent( + data: Partial | any, + eventName: IssueCommentEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "ISSUE_COMMENT_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + issueId: data?.issue, + }; + else payload = data; + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackIssueMovedToCycleOrModuleEvent( + data: any, + eventName: + | "ISSUE_MOVED_TO_CYCLE" + | "ISSUE_MOVED_TO_MODULE" + | "ISSUE_MOVED_TO_CYCLE_IN_BULK" + | "ISSUE_MOVED_TO_MODULE_IN_BULK", + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssueBulkDeleteEvent(data: any, user: ICurrentUserResponse | undefined): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName: "ISSUE_BULK_DELETE", + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssueLabelEvent( + data: any, + eventName: IssueLabelEventType, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackStateEvent( + data: IState | any, + eventName: StateEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "STATE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + stateId: data.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackCycleEvent( + data: ICycle | any, + eventName: CycleEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "CYCLE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + cycleId: data.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackModuleEvent( + data: IModule | any, + eventName: ModuleEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "MODULE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + moduleId: data.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackPageEvent( + data: Partial | any, + eventName: PagesEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "PAGE_DELETE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + pageId: data.id, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackPageBlockEvent( + data: Partial | IIssue, + eventName: PageBlocksEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "PAGE_BLOCK_DELETE" && eventName !== "PAGE_BLOCK_CONVERTED_TO_ISSUE") + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + pageId: (data as IPageBlock)?.page, + pageBlockId: data.id, + }; + else if (eventName === "PAGE_BLOCK_CONVERTED_TO_ISSUE") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + issueId: data?.id, + }; + } else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackAskGptEvent( + data: IGptResponse, + eventName: GptEventType, + user: ICurrentUserResponse | undefined + ): Promise { + const payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectIdentifier: data?.project_detail?.identifier, + projectName: data?.project_detail?.name, + count: data?.count, + }; + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackUseGPTResponseEvent( + data: IIssue | IPageBlock, + eventName: GptEventType, + user: ICurrentUserResponse | undefined + ): Promise { + if (!trackEvent) return; + + let payload: any; + + if (eventName === "USE_GPT_RESPONSE_IN_ISSUE") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectIdentifier: data?.project_detail?.identifier, + projectName: data?.project_detail?.name, + issueId: data.id, + }; + } else if (eventName === "USE_GPT_RESPONSE_IN_PAGE_BLOCK") { + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectIdentifier: data?.project_detail?.identifier, + projectName: data?.project_detail?.name, + pageId: (data as IPageBlock)?.page, + pageBlockId: data.id, + }; + } + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackViewEvent( + data: IView, + eventName: ViewEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName === "VIEW_DELETE") payload = data; + else + payload = { + labels: Boolean(data.query_data.labels), + assignees: Boolean(data.query_data.assignees), + priority: Boolean(data.query_data.priority), + state: Boolean(data.query_data.state), + created_by: Boolean(data.query_data.created_by), + }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackMiscellaneousEvent( + data: any, + eventName: MiscellaneousEventType, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackAppIntegrationEvent( + data: any, + eventName: IntegrationEventType, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackGitHubSyncEvent( + data: any, + eventName: GitHubSyncEventType, + user: ICurrentUserResponse | undefined + ): Promise { + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...data, + }, + user: user, + }, + }); + } + + async trackIssueEstimateEvent( + data: { estimate: IEstimate }, + eventName: IssueEstimateEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName === "ESTIMATE_DELETE") payload = data; + else + payload = { + workspaceId: data?.estimate?.workspace_detail?.id, + workspaceName: data?.estimate?.workspace_detail?.name, + workspaceSlug: data?.estimate?.workspace_detail?.slug, + projectId: data?.estimate?.project_detail?.id, + projectName: data?.estimate?.project_detail?.name, + projectIdentifier: data?.estimate?.project_detail?.identifier, + estimateId: data.estimate?.id, + }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackImporterEvent( + data: any, + eventName: ImporterEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName === "GITHUB_IMPORTER_DELETE" || eventName === "JIRA_IMPORTER_DELETE") + payload = data; + else + payload = { + workspaceId: data?.workspace_detail?.id, + workspaceName: data?.workspace_detail?.name, + workspaceSlug: data?.workspace_detail?.slug, + projectId: data?.project_detail?.id, + projectName: data?.project_detail?.name, + projectIdentifier: data?.project_detail?.identifier, + }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackAnalyticsEvent( + data: any, + eventName: AnalyticsEventType, + user: ICurrentUserResponse | undefined + ): Promise { + const payload = { ...data }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: payload, + user: user, + }, + }); + } + + // track exporter function\ + async trackExporterEvent( + data: any, + eventName: ExporterEventType, + user: ICurrentUserResponse | undefined + ): Promise { + const payload = { ...data }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + // TODO: add types to the data + async trackInboxEvent( + data: any, + eventName: InboxEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName !== "INBOX_DELETE") + payload = { + issue: data?.issue?.id, + inbox: data?.id, + workspaceId: data?.issue?.workspace_detail?.id, + workspaceName: data?.issue?.workspace_detail?.name, + workspaceSlug: data?.issue?.workspace_detail?.slug, + projectId: data?.issue?.project_detail?.id, + projectName: data?.issue?.project_detail?.name, + }; + else payload = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: { + ...payload, + }, + user: user, + }, + }); + } + + async trackReactionEvent( + data: IssueReaction | IssueCommentReaction, + eventName: ReactionEventType, + user: ICurrentUserResponse | undefined + ): Promise { + let payload: any; + if (eventName === "ISSUE_REACTION_DELETE" || eventName === "ISSUE_COMMENT_REACTION_DELETE") + payload = data; + else + payload = { + workspaceId: data?.workspace, + projectId: data?.project, + reaction: data?.reaction, + }; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: payload, + user: user, + }, + }); + } + + // project publish settings track events starts + async trackProjectPublishSettingsEvent( + data: any, + eventName: string, + user: ICurrentUserResponse | undefined + ): Promise { + const payload: any = data; + + return this.request({ + url: "/api/track-event", + method: "POST", + data: { + eventName, + extra: payload, + user: user, + }, + }); + } + + // project publish settings track events ends +} + +const trackEventServices = new TrackEventServices(); + +export default trackEventServices; diff --git a/packages/plane-services/user.service.ts b/packages/plane-services/user.service.ts new file mode 100644 index 000000000..0e5def647 --- /dev/null +++ b/packages/plane-services/user.service.ts @@ -0,0 +1,200 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +import type { + ICurrentUserResponse, + IIssue, + IUser, + IUserActivityResponse, + IUserProfileData, + IUserProfileProjectSegregation, + IUserWorkspaceDashboard, +} from "types"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class UserService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + currentUserConfig() { + return { + url: `${this.baseURL}/api/users/me/`, + headers: this.getHeaders(), + }; + } + + async userIssues( + workspaceSlug: string, + params: any + ): Promise< + | { + [key: string]: IIssue[]; + } + | IIssue[] + > { + return this.get(`/api/workspaces/${workspaceSlug}/my-issues/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async currentUser(): Promise { + return this.get("/api/users/me/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateUser(data: Partial): Promise { + return this.patch("/api/users/me/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateUserOnBoard({ userRole }: any, user: ICurrentUserResponse | undefined): Promise { + return this.patch("/api/users/me/onboard/", { + is_onboarded: true, + }) + .then((response) => { + if (trackEvent) + trackEventServices.trackUserOnboardingCompleteEvent( + { + user_role: userRole ?? "None", + }, + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateUserTourCompleted(user: ICurrentUserResponse): Promise { + return this.patch("/api/users/me/tour-completed/", { + is_tour_completed: true, + }) + .then((response) => { + if (trackEvent) + trackEventServices.trackUserTourCompleteEvent( + { + user_role: user.role ?? "None", + }, + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserWorkspaceActivity(workspaceSlug: string): Promise { + return this.get(`/api/users/workspaces/${workspaceSlug}/activities/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async userWorkspaceDashboard( + workspaceSlug: string, + month: number + ): Promise { + return this.get(`/api/users/me/workspaces/${workspaceSlug}/dashboard/`, { + params: { + month: month, + }, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async forgotPassword(data: { email: string }): Promise { + return this.post(`/api/forgot-password/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async resetPassword( + uidb64: string, + token: string, + data: { + new_password: string; + confirm_password: string; + } + ): Promise { + return this.post(`/api/reset-password/${uidb64}/${token}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileData(workspaceSlug: string, userId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/user-stats/${userId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileProjectsSegregation( + workspaceSlug: string, + userId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/user-profile/${userId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileActivity( + workspaceSlug: string, + userId: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/user-activity/${userId}/?per_page=15`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getUserProfileIssues( + workspaceSlug: string, + userId: string, + params: any + ): Promise< + | { + [key: string]: IIssue[]; + } + | IIssue[] + > { + return this.get(`/api/workspaces/${workspaceSlug}/user-issues/${userId}/`, { + params, + }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new UserService(); diff --git a/packages/plane-services/views.service.ts b/packages/plane-services/views.service.ts new file mode 100644 index 000000000..e1d25925e --- /dev/null +++ b/packages/plane-services/views.service.ts @@ -0,0 +1,146 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; +import { ICurrentUserResponse } from "types"; + +// types +import { IView } from "types/views"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class ViewServices extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async createView( + workspaceSlug: string, + projectId: string, + data: IView, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_CREATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateView( + workspaceSlug: string, + projectId: string, + viewId: string, + data: IView, + user: ICurrentUserResponse | undefined + ): Promise { + return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, data) + .then((response) => { + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async patchView( + workspaceSlug: string, + projectId: string, + viewId: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`, + data + ) + .then((response) => { + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_UPDATE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteView( + workspaceSlug: string, + projectId: string, + viewId: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`) + .then((response) => { + if (trackEvent) trackEventServices.trackViewEvent(response?.data, "VIEW_DELETE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getViews(workspaceSlug: string, projectId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getViewDetails(workspaceSlug: string, projectId: string, viewId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getViewIssues(workspaceSlug: string, projectId: string, viewId: string): Promise { + return this.get( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/views/${viewId}/issues/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async addViewToFavorites( + workspaceSlug: string, + projectId: string, + data: { + view: string; + } + ): Promise { + return this.post( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/`, + data + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeViewFromFavorites( + workspaceSlug: string, + projectId: string, + viewId: string + ): Promise { + return this.delete( + `/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-views/${viewId}/` + ) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new ViewServices(); diff --git a/packages/plane-services/web-waitlist.service.ts b/packages/plane-services/web-waitlist.service.ts new file mode 100644 index 000000000..b56906bba --- /dev/null +++ b/packages/plane-services/web-waitlist.service.ts @@ -0,0 +1,22 @@ +// services +import APIService from "services/api.service"; + +// types +import { IWebWaitListResponse } from "types"; + +class WebWailtListServices extends APIService { + constructor() { + const origin = typeof window !== "undefined" ? window.location.origin || "" : ""; + super(origin); + } + + async create({ email }: { email: string }): Promise { + return this.post(`/api/web-waitlist`, { email: email }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } +} + +export default new WebWailtListServices(); diff --git a/packages/plane-services/workspace.service.ts b/packages/plane-services/workspace.service.ts new file mode 100644 index 000000000..8097253e6 --- /dev/null +++ b/packages/plane-services/workspace.service.ts @@ -0,0 +1,279 @@ +// services +import APIService from "services/api.service"; +import trackEventServices from "services/track-event.service"; + +const { NEXT_PUBLIC_API_BASE_URL } = process.env; + +// types +import { + IWorkspace, + IWorkspaceMember, + IWorkspaceMemberInvitation, + ILastActiveWorkspaceDetails, + IWorkspaceSearchResults, + IProductUpdateResponse, + ICurrentUserResponse, + IWorkspaceBulkInviteFormData, + IWorkspaceViewProps, +} from "types"; + +const trackEvent = + process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; + +class WorkspaceService extends APIService { + constructor() { + super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); + } + + async userWorkspaces(): Promise { + return this.get("/api/users/me/workspaces/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspace(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async createWorkspace( + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post("/api/workspaces/", data) + .then((response) => { + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateWorkspace( + workspaceSlug: string, + data: Partial, + user: ICurrentUserResponse | undefined + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "UPDATE_WORKSPACE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteWorkspace( + workspaceSlug: string, + user: ICurrentUserResponse | undefined + ): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/`) + .then((response) => { + if (trackEvent) + trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async inviteWorkspace( + workspaceSlug: string, + data: IWorkspaceBulkInviteFormData, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/invite/`, data) + .then((response) => { + if (trackEvent) + trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE", user); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async joinWorkspace( + workspaceSlug: string, + invitationId: string, + data: any, + user: ICurrentUserResponse | undefined + ): Promise { + return this.post( + `/api/users/me/invitations/workspaces/${workspaceSlug}/${invitationId}/join/`, + data, + { + headers: {}, + } + ) + .then((response) => { + if (trackEvent) + trackEventServices.trackWorkspaceEvent( + response.data, + "WORKSPACE_USER_INVITE_ACCEPT", + user + ); + return response?.data; + }) + .catch((error) => { + throw error?.response?.data; + }); + } + + async joinWorkspaces(data: any): Promise { + return this.post("/api/users/me/invitations/workspaces/", data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getLastActiveWorkspaceAndProjects(): Promise { + return this.get("/api/users/last-visited-workspace/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async userWorkspaceInvitations(): Promise { + return this.get("/api/users/me/invitations/workspaces/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceMembers(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceMembersWithEmail(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/members/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceMemberMe(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/me/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateWorkspaceView( + workspaceSlug: string, + data: { view_props: IWorkspaceViewProps } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/workspace-views/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async updateWorkspaceMember( + workspaceSlug: string, + memberId: string, + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/members/${memberId}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteWorkspaceMember(workspaceSlug: string, memberId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/members/${memberId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceInvitations(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/invitations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceInvitationsWithEmail( + workspaceSlug: string + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/invitations/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async getWorkspaceInvitation(invitationId: string): Promise { + return this.get(`/api/users/me/invitations/${invitationId}/`, { headers: {} }) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async deleteWorkspaceInvitations(workspaceSlug: string, invitationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/invitations/${invitationId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async workspaceSlugCheck(slug: string): Promise { + return this.get(`/api/workspace-slug-check/?slug=${slug}`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async searchWorkspace( + workspaceSlug: string, + params: { + project_id?: string; + search: string; + workspace_search: boolean; + } + ): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/search/`, { + params, + }) + .then((res) => res?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + async getProductUpdates(): Promise { + return this.get("/api/release-notes/") + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } +} + +export default new WorkspaceService();