mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-18 21:22:15 +01:00
add basic crud frontend for clients, tags and projects
This commit is contained in:
45
resources/js/Pages/Clients.vue
Normal file
45
resources/js/Pages/Clients.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
import MainContainer from '@/Pages/MainContainer.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
import { PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import TabBar from '@/Components/Common/TabBar/TabBar.vue';
|
||||
import TabBarItem from '@/Components/Common/TabBar/TabBarItem.vue';
|
||||
import { UserCircleIcon } from '@heroicons/vue/20/solid';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useClientsStore } from '@/utils/useClients';
|
||||
import ClientTable from '@/Components/Common/Client/ClientTable.vue';
|
||||
import ClientCreateModal from '@/Components/Common/Client/ClientCreateModal.vue';
|
||||
|
||||
onMounted(() => {
|
||||
useClientsStore().fetchClients();
|
||||
});
|
||||
|
||||
const createClient = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Clients" data-testid="clients_view">
|
||||
<MainContainer
|
||||
class="py-5 border-b border-default-background-separator flex justify-between items-center">
|
||||
<div class="flex items-center space-x-6">
|
||||
<h3
|
||||
class="text-white font-bold text-base flex items-center space-x-2.5">
|
||||
<UserCircleIcon
|
||||
class="w-6 text-icon-default"></UserCircleIcon>
|
||||
<span> Clients </span>
|
||||
</h3>
|
||||
<TabBar>
|
||||
<TabBarItem>All</TabBarItem>
|
||||
<TabBarItem active>Active</TabBarItem>
|
||||
<TabBarItem>Archived</TabBarItem>
|
||||
</TabBar>
|
||||
</div>
|
||||
<SecondaryButton :icon="PlusIcon" @click="createClient = true"
|
||||
>Create Client</SecondaryButton
|
||||
>
|
||||
<ClientCreateModal v-model:show="createClient"></ClientCreateModal>
|
||||
</MainContainer>
|
||||
<ClientTable></ClientTable>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -50,11 +50,11 @@ const props = defineProps<{
|
||||
<template>
|
||||
<AppLayout title="Dashboard" data-testid="dashboard_view">
|
||||
<MainContainer
|
||||
class="pt-8 pb-6 border-b border-default-background-seperator">
|
||||
class="pt-8 pb-6 border-b border-default-background-separator">
|
||||
<TimeTracker></TimeTracker>
|
||||
</MainContainer>
|
||||
<MainContainer
|
||||
class="grid gap-x-6 grid-cols-2 xl:grid-cols-4 pt-5 pb-6 border-b border-default-background-seperator items-stretch">
|
||||
class="grid gap-x-6 grid-cols-2 xl:grid-cols-4 pt-5 pb-6 border-b border-default-background-separator items-stretch">
|
||||
<RecentlyTrackedTasksCard
|
||||
:latestTasks="props.latestTasks"></RecentlyTrackedTasksCard>
|
||||
<LastSevenDaysCard
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div class="sm:px-6 lg:px-8 3xl:px-12 mx-auto">
|
||||
<div class="px-4 sm:px-6 lg:px-8 3xl:px-12 mx-auto">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
47
resources/js/Pages/Members.vue
Normal file
47
resources/js/Pages/Members.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import MainContainer from '@/Pages/MainContainer.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
import { PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import { UserGroupIcon } from '@heroicons/vue/20/solid';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import TabBar from '@/Components/Common/TabBar/TabBar.vue';
|
||||
import TabBarItem from '@/Components/Common/TabBar/TabBarItem.vue';
|
||||
import { ref } from 'vue';
|
||||
import MemberTable from '@/Components/Common/Member/MemberTable.vue';
|
||||
import MemberInviteModal from '@/Components/Common/Member/MemberInviteModal.vue';
|
||||
import type { Role } from '@/types/jetstream';
|
||||
|
||||
const inviteMember = ref(false);
|
||||
|
||||
defineProps<{
|
||||
availableRoles: Role[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Members" data-testid="members_view">
|
||||
<MainContainer
|
||||
class="py-5 border-b border-default-background-separator flex justify-between items-center">
|
||||
<div class="flex items-center space-x-6">
|
||||
<h3
|
||||
class="text-white font-bold text-base flex items-center space-x-2.5">
|
||||
<UserGroupIcon
|
||||
class="w-6 text-icon-default"></UserGroupIcon>
|
||||
<span> Members </span>
|
||||
</h3>
|
||||
<TabBar>
|
||||
<TabBarItem active>All</TabBarItem>
|
||||
<TabBarItem>Active</TabBarItem>
|
||||
<TabBarItem>Inactive</TabBarItem>
|
||||
</TabBar>
|
||||
</div>
|
||||
<SecondaryButton :icon="PlusIcon" @click="inviteMember = true"
|
||||
>Invite member</SecondaryButton
|
||||
>
|
||||
<MemberInviteModal
|
||||
:available-roles="availableRoles"
|
||||
v-model:show="inviteMember"></MemberInviteModal>
|
||||
</MainContainer>
|
||||
<MemberTable></MemberTable>
|
||||
</AppLayout>
|
||||
</template>
|
||||
44
resources/js/Pages/Projects.vue
Normal file
44
resources/js/Pages/Projects.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import MainContainer from '@/Pages/MainContainer.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
import { FolderIcon, PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import TabBarItem from '@/Components/Common/TabBar/TabBarItem.vue';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import TabBar from '@/Components/Common/TabBar/TabBar.vue';
|
||||
import ProjectTable from '@/Components/Common/Project/ProjectTable.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useProjectsStore } from '@/utils/useProjects';
|
||||
import ProjectCreateModal from '@/Components/Common/Project/ProjectCreateModal.vue';
|
||||
|
||||
onMounted(() => {
|
||||
useProjectsStore().fetchProjects();
|
||||
});
|
||||
|
||||
const createProject = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Projects" data-testid="projects_view">
|
||||
<MainContainer
|
||||
class="py-5 border-b border-default-background-separator flex justify-between items-center">
|
||||
<div class="flex items-center space-x-6">
|
||||
<h3
|
||||
class="text-white font-bold text-base flex items-center space-x-2.5">
|
||||
<FolderIcon class="w-6 text-icon-default"></FolderIcon>
|
||||
<span> Projects </span>
|
||||
</h3>
|
||||
<TabBar>
|
||||
<TabBarItem>All</TabBarItem>
|
||||
<TabBarItem active>Active</TabBarItem>
|
||||
<TabBarItem>Archived</TabBarItem>
|
||||
</TabBar>
|
||||
</div>
|
||||
<SecondaryButton :icon="PlusIcon" @click="createProject = true"
|
||||
>Create Project</SecondaryButton
|
||||
>
|
||||
<ProjectCreateModal
|
||||
v-model:show="createProject"></ProjectCreateModal>
|
||||
</MainContainer>
|
||||
<ProjectTable></ProjectTable>
|
||||
</AppLayout>
|
||||
</template>
|
||||
13
resources/js/Pages/Reporting.vue
Normal file
13
resources/js/Pages/Reporting.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import MainContainer from '@/Pages/MainContainer.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Reporting" data-testid="reporting_view">
|
||||
<MainContainer
|
||||
class="py-8 border-b border-default-background-separator">
|
||||
Reporting is coming soon™
|
||||
</MainContainer>
|
||||
</AppLayout>
|
||||
</template>
|
||||
31
resources/js/Pages/Tags.vue
Normal file
31
resources/js/Pages/Tags.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import MainContainer from '@/Pages/MainContainer.vue';
|
||||
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||
import { FolderIcon, PlusIcon } from '@heroicons/vue/16/solid';
|
||||
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||
import { ref } from 'vue';
|
||||
import TagTable from '@/Components/Common/Tag/TagTable.vue';
|
||||
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
|
||||
|
||||
const createTag = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Tags" data-testid="tags_view">
|
||||
<MainContainer
|
||||
class="py-5 border-b border-default-background-separator flex justify-between items-center">
|
||||
<div class="flex items-center space-x-6">
|
||||
<h3
|
||||
class="text-white font-bold text-base flex items-center space-x-2.5">
|
||||
<FolderIcon class="w-6 text-icon-default"></FolderIcon>
|
||||
<span> Tags </span>
|
||||
</h3>
|
||||
</div>
|
||||
<SecondaryButton :icon="PlusIcon" @click="createTag = true"
|
||||
>Create Tag</SecondaryButton
|
||||
>
|
||||
<TagCreateModal v-model:show="createTag"></TagCreateModal>
|
||||
</MainContainer>
|
||||
<TagTable></TagTable>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -82,7 +82,8 @@ const updateTeamName = () => {
|
||||
class="mt-1 block w-full border-input-border bg-input-background text-white focus:border-input-border-active rounded-md shadow-sm">
|
||||
<option value="" disabled>Select a currency</option>
|
||||
<option
|
||||
v-for="(currencyTranslated, currencyKey) in $page.props.currencies"
|
||||
v-for="(currencyTranslated, currencyKey) in $page.props
|
||||
.currencies"
|
||||
:key="currencyKey"
|
||||
:value="currencyKey">
|
||||
{{ currencyKey }} - {{ currencyTranslated }}
|
||||
|
||||
@@ -49,7 +49,7 @@ const groupedTimeEntries = computed(() => {
|
||||
<template>
|
||||
<AppLayout title="Dashboard" data-testid="dashboard_view">
|
||||
<MainContainer
|
||||
class="py-8 border-b border-default-background-seperator">
|
||||
class="py-8 border-b border-default-background-separator">
|
||||
<TimeTracker></TimeTracker>
|
||||
</MainContainer>
|
||||
<div v-for="(value, key) in groupedTimeEntries" :key="key">
|
||||
|
||||
Reference in New Issue
Block a user