seperate project types, make tag dropdown location configurable, update api client

This commit is contained in:
Gregor Vostrak
2024-08-05 15:02:51 +02:00
parent 04bb8e50a7
commit 10cc5cf42a
9 changed files with 37 additions and 58 deletions

View File

@@ -218,7 +218,7 @@ const UserResource = z
week_start: Weekday,
})
.passthrough();
const PersonalMemberResource = z
const PersonalMembershipResource = z
.object({
id: z.string(),
organization: z
@@ -227,6 +227,7 @@ const PersonalMemberResource = z
role: z.string(),
})
.passthrough();
const PersonalMembershipCollection = z.array(PersonalMembershipResource);
export const schemas = {
ClientResource,
@@ -262,7 +263,8 @@ export const schemas = {
TimeEntryUpdateRequest,
Weekday,
UserResource,
PersonalMemberResource,
PersonalMembershipResource,
PersonalMembershipCollection,
};
const endpoints = makeApi([
@@ -2504,42 +2506,12 @@ If the group parameters are all set to `null` or are all missing, the
},
{
method: 'get',
path: '/v1/users/me/members',
path: '/v1/users/me/memberships',
alias: 'getMyMemberships',
description: `This endpoint is independent of organization.`,
requestFormat: 'json',
response: z
.object({
data: z.array(PersonalMemberResource),
links: z
.object({
first: z.union([z.string(), z.null()]),
last: z.union([z.string(), z.null()]),
prev: z.union([z.string(), z.null()]),
next: z.union([z.string(), z.null()]),
})
.passthrough(),
meta: z
.object({
current_page: z.number().int(),
from: z.union([z.number(), z.null()]),
last_page: z.number().int(),
links: z.array(
z
.object({
url: z.union([z.string(), z.null()]),
label: z.string(),
active: z.boolean(),
})
.passthrough()
),
path: z.union([z.string(), z.null()]),
per_page: z.number().int(),
to: z.union([z.number(), z.null()]),
total: z.number().int(),
})
.passthrough(),
})
.object({ data: PersonalMembershipCollection })
.passthrough(),
errors: [
{

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import type { BillableKey } from '@/utils/useProjects';
import Badge from '@/Components/Common/Badge.vue';
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
import type { BillableKey } from '@/types/projects';
const model = defineModel<BillableKey>({
default: 'default-rate',

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import SelectDropdown from '@/Components/Common/SelectDropdown.vue';
import type { BillableKey } from '@/utils/useProjects';
import Badge from '@/Components/Common/Badge.vue';
import { ChevronDownIcon } from '@heroicons/vue/20/solid';
import type { BillableKey } from '@/types/projects';
const model = defineModel<BillableKey>({
default: 'non-billable',

View File

@@ -3,7 +3,7 @@ import InputLabel from '@/Components/InputLabel.vue';
import BillableRateInput from '@/Components/Common/BillableRateInput.vue';
import ProjectBillableSelect from '@/Components/Common/Project/ProjectBillableSelect.vue';
import { computed, onMounted, ref, watch } from 'vue';
import type { BillableKey } from '@/utils/useProjects';
import type { BillableKey } from '@/types/projects';
const billableRateSelect = ref<BillableKey>('non-billable');

View File

@@ -5,11 +5,18 @@ import { type Component, computed, nextTick, ref, watch } from 'vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import MultiselectDropdownItem from '@/Components/Common/MultiselectDropdownItem.vue';
import type { Tag } from '@/utils/api';
import type { Placement } from '@floating-ui/vue';
const props = defineProps<{
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
}>();
const props = withDefaults(
defineProps<{
tags: Tag[];
createTag: (name: string) => Promise<Tag | undefined>;
align: Placement;
}>(),
{
align: 'bottom-start',
}
);
const model = defineModel<string[]>({
default: [],
@@ -164,7 +171,7 @@ const showCreateTagModal = ref(false);
<Dropdown
@submit="emit('submit')"
v-model="open"
align="bottom-start"
:align="align"
:closeOnContentClick="false">
<template #trigger>
<slot name="trigger"></slot>
@@ -180,7 +187,7 @@ const showCreateTagModal = ref(false);
ref="searchInput"
class="bg-card-background border-0 placeholder-muted text-sm text-white py-2.5 focus:ring-0 border-b border-card-background-separator focus:border-card-background-separator w-full"
placeholder="Search for a Tag..." />
<div ref="dropdownViewport" class="w-60">
<div ref="dropdownViewport" class="w-60 max-h-48 overflow-y-scroll">
<div
v-for="tag in filteredTags"
:key="tag.id"
@@ -197,18 +204,18 @@ const showCreateTagModal = ref(false);
@click="toggleTag(tag.id)"
:name="tag.name"></MultiselectDropdownItem>
</div>
<div class="hover:bg-card-background-active rounded-b-lg">
<button
@click="
open = false;
showCreateTagModal = true;
"
class="text-white flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator">
<PlusCircleIcon
class="w-5 flex-shrink-0 text-icon-default"></PlusCircleIcon>
<span>Create new Tag</span>
</button>
</div>
</div>
<div class="hover:bg-card-background-active rounded-b-lg">
<button
@click="
open = false;
showCreateTagModal = true;
"
class="text-white w-full flex space-x-3 items-center px-4 py-3 text-xs font-semibold border-t border-card-background-separator">
<PlusCircleIcon
class="w-5 flex-shrink-0 text-icon-default"></PlusCircleIcon>
<span>Create new Tag</span>
</button>
</div>
</template>
</Dropdown>

View File

@@ -24,6 +24,7 @@ const timeEntryTags = computed<Tag[]>(() => {
<template>
<TagDropdown
:tags="tags"
align="bottom-end"
:createTag
@changed="emit('changed', model)"
v-model="model">

View File

@@ -78,7 +78,7 @@ function onToggleButtonPress(newState: boolean) {
data-testid="dashboard_timer">
<div
class="flex flex-col sm:flex-row w-full justify-between rounded-lg bg-card-background border-card-border border transition shadow-card">
<div class="flex items-center pr-6">
<div class="flex flex-1 items-center pr-6">
<input
placeholder="What are you working on?"
data-testid="time_entry_description"

1
resources/js/types/projects.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export type BillableKey = 'non-billable' | 'default-rate' | 'custom-rate';

View File

@@ -10,8 +10,6 @@ import type {
import { getCurrentOrganizationId } from '@/utils/useUser';
import { useNotificationsStore } from '@/utils/notification';
export type BillableKey = 'non-billable' | 'default-rate' | 'custom-rate';
export const useProjectsStore = defineStore('projects', () => {
const projectResponse = ref<ProjectResponse | null>(null);
const { handleApiRequestNotifications } = useNotificationsStore();