add basic crud frontend for clients, tags and projects

This commit is contained in:
Gregor Vostrak
2024-04-03 16:07:23 +02:00
parent 824e3d99ae
commit 0081aa7a6e
77 changed files with 2670 additions and 330 deletions

View File

@@ -1,4 +1,8 @@
import type { ApiOf, ZodiosResponseByAlias } from '@zodios/core';
import type {
ApiOf,
ZodiosResponseByAlias,
ZodiosBodyByAlias,
} from '@zodios/core';
import { api } from '../../../openapi.json.client';
export type SolidTimeApi = ApiOf<typeof api>;
@@ -15,5 +19,29 @@ export type ProjectResponse = ZodiosResponseByAlias<
>;
export type Project = ProjectResponse['data'][0];
export type CreateProjectBody = ZodiosBodyByAlias<
SolidTimeApi,
'createProject'
>;
export type CreateClientBody = ZodiosBodyByAlias<SolidTimeApi, 'createClient'>;
export type TagIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getTags'>;
export type Tag = TagIndexResponse['data'][0];
export type TaskIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getTasks'>;
export type Task = TaskIndexResponse['data'][0];
export type ClientIndexResponse = ZodiosResponseByAlias<
SolidTimeApi,
'getClients'
>;
export type Client = ClientIndexResponse['data'][0];
export type MemberIndexResponse = ZodiosResponseByAlias<
SolidTimeApi,
'getMembers'
>;
export type Member = MemberIndexResponse['data'][0];
export type CreateTagBody = ZodiosBodyByAlias<SolidTimeApi, 'createTag'>;

View File

@@ -1,4 +1,4 @@
const colors = [
export const colors = [
'#ef5350',
'#ec407a',
'#ab47bc',

View File

@@ -0,0 +1,61 @@
import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client';
import { computed, ref } from 'vue';
import type {
CreateClientBody,
ClientIndexResponse,
Client,
} from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser';
export const useClientsStore = defineStore('clients', () => {
const clientResponse = ref<ClientIndexResponse | null>(null);
async function fetchClients() {
const organization = getCurrentOrganizationId();
if (organization) {
clientResponse.value = await api.getClients({
params: {
organization: organization,
},
});
}
}
async function createClient(
clientBody: CreateClientBody
): Promise<Client | undefined> {
const organization = getCurrentOrganizationId();
if (organization) {
const response = await api.createClient(clientBody, {
params: {
organization: organization,
},
});
await fetchClients();
return response.data;
}
}
async function deleteClient(clientId: string) {
const organization = getCurrentOrganizationId();
if (organization) {
await api.deleteClient(
{},
{
params: {
organization: organization,
client: clientId,
},
}
);
await fetchClients();
}
}
const clients = computed<Client[]>(() => {
return clientResponse.value?.data || [];
});
return { clients, fetchClients, createClient, deleteClient };
});

View File

@@ -0,0 +1,26 @@
import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client';
import { computed, ref } from 'vue';
import type { Member, MemberIndexResponse } from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser';
export const useMembersStore = defineStore('members', () => {
const membersResponse = ref<MemberIndexResponse | null>(null);
async function fetchMembers() {
const organization = getCurrentOrganizationId();
if (organization) {
membersResponse.value = await api.getMembers({
params: {
organization: organization,
},
});
}
}
const members = computed<Member[]>(() => {
return membersResponse.value?.data || [];
});
return { members, fetchMembers };
});

View File

@@ -1,7 +1,7 @@
import { defineStore } from 'pinia';
import { api } from '../../../openapi.json.client';
import { computed, ref } from 'vue';
import type { Project, ProjectResponse } from '@/utils/api';
import type { CreateProjectBody, Project, ProjectResponse } from '@/utils/api';
import { getCurrentOrganizationId } from '@/utils/useUser';
export const useProjectsStore = defineStore('projects', () => {
@@ -18,9 +18,37 @@ export const useProjectsStore = defineStore('projects', () => {
}
}
async function createProject(projectBody: CreateProjectBody) {
const organization = getCurrentOrganizationId();
if (organization) {
await api.createProject(projectBody, {
params: {
organization: organization,
},
});
await fetchProjects();
}
}
async function deleteProject(projectId: string) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
await api.deleteProject(
{},
{
params: {
organization: organizationId,
project: projectId,
},
}
);
await fetchProjects();
}
}
const projects = computed<Project[]>(
() => projectResponse.value?.data || []
);
return { projects, fetchProjects };
return { projects, fetchProjects, createProject, deleteProject };
});

View File

@@ -23,6 +23,22 @@ export const useTagsStore = defineStore('tags', () => {
}
}
async function deleteTag(tagId: string) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
await api.deleteTag(
{},
{
params: {
organization: organizationId,
tag: tagId,
},
}
);
await fetchTags();
}
}
async function createTag(name: string) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
@@ -45,5 +61,5 @@ export const useTagsStore = defineStore('tags', () => {
}
}
return { tags, fetchTags, createTag };
return { tags, fetchTags, createTag, deleteTag };
});

View File

@@ -0,0 +1,69 @@
import { defineStore } from 'pinia';
import { getCurrentOrganizationId } from '@/utils/useUser';
import { api } from '../../../openapi.json.client';
import { reactive, ref } from 'vue';
import type { Task } from '@/utils/api';
export const useTasksStore = defineStore('tasks', () => {
const tasks = ref<Task[]>(reactive([]));
async function fetchTasks() {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
const tasksResponse = await api.getTasks({
params: {
organization: organizationId,
},
});
tasks.value = tasksResponse.data;
}
}
async function updateTask(task: Task) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
await api.updateTask(task, {
params: {
organization: organizationId,
task: task.id,
},
});
}
}
async function createTask(task: Task) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
await api.createTask(task, {
params: {
organization: organizationId,
},
});
await fetchTasks();
}
}
async function deleteTask(taskId: string) {
const organizationId = getCurrentOrganizationId();
if (organizationId) {
await api.deleteTask(
{},
{
params: {
organization: organizationId,
task: taskId,
},
}
);
await fetchTasks();
}
}
return {
tasks,
fetchTasks,
updateTask,
createTask,
deleteTask,
};
});

View File

@@ -18,7 +18,7 @@ export const useTimeEntriesStore = defineStore('timeEntries', () => {
organization: organizationId,
},
queries: {
only_full_dates: true,
only_full_dates: 'true',
},
});
timeEntries.value = timeEntriesResponse.data;
@@ -37,7 +37,7 @@ export const useTimeEntriesStore = defineStore('timeEntries', () => {
organization: organizationId,
},
queries: {
only_full_dates: true,
only_full_dates: 'true',
before: dayjs(latestTimeEntry.start).utc().format(),
},
});