Skip to content

Commit

Permalink
add projects detail page, task create / delete
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregor Vostrak authored and Onatcer committed Apr 8, 2024
1 parent 2a7329d commit 0ef6d63
Show file tree
Hide file tree
Showing 32 changed files with 740 additions and 222 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ module.exports = {
extends: ['plugin:vue/vue3-essential', '@vue/eslint-config-typescript/recommended', '@vue/eslint-config-prettier'],
rules: {
'vue/multi-word-component-names': 'off',
}
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": "error",
},
plugins: ['unused-imports'],
}
109 changes: 109 additions & 0 deletions e2e/tasks.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { expect, Page } from '@playwright/test';
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';
import { test } from '../playwright/fixtures';

async function goToProjectsOverview(page: Page) {
await page.goto(PLAYWRIGHT_BASE_URL + '/projects');
}

// Create new project via modal
test('test that creating and deleting a new tag in a new project works', async ({
page,
}) => {
const newProjectName =
'New Project ' + Math.floor(1 + Math.random() * 10000);
await goToProjectsOverview(page);
await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByPlaceholder('Project Name').fill(newProjectName);
await Promise.all([
page.getByRole('button', { name: 'Create Project' }).nth(1).click(),
page.waitForResponse(
async (response) =>
response.url().includes('/projects') &&
response.request().method() === 'POST' &&
response.status() === 201 &&
(await response.json()).data.id !== null &&
(await response.json()).data.color !== null &&
(await response.json()).data.client_id === null &&
(await response.json()).data.name === newProjectName
),
]);

await expect(page.getByTestId('project_table')).toContainText(
newProjectName
);

await page.getByText(newProjectName).click();

const newTaskName = 'New Project ' + Math.floor(1 + Math.random() * 10000);

await page.getByRole('button', { name: 'Create Task' }).click();
await page.getByPlaceholder('Task Name').fill(newTaskName);

await Promise.all([
page.getByRole('button', { name: 'Create Task' }).nth(1).click(),
page.waitForResponse(
async (response) =>
response.url().includes('/tasks') &&
response.request().method() === 'POST' &&
response.status() === 201 &&
(await response.json()).data.id !== null &&
(await response.json()).data.project_id !== null &&
(await response.json()).data.name === newTaskName
),
]);

await expect(page.getByTestId('task_table')).toContainText(newTaskName);

const taskMoreButton = page.locator(
"[aria-label='Actions for Task " + newTaskName + "']"
);
taskMoreButton.click();
const taskDeleteButton = page.locator(
"[aria-label='Delete Task " + newTaskName + "']"
);

await Promise.all([
taskDeleteButton.click(),
page.waitForResponse(
async (response) =>
response.url().includes('/tasks') &&
response.request().method() === 'DELETE' &&
response.status() === 204
),
]);
await expect(page.getByTestId('task_table')).not.toContainText(newTaskName);

await goToProjectsOverview(page);

const moreButton = page.locator(
"[aria-label='Actions for Project " + newProjectName + "']"
);
moreButton.click();
const deleteButton = page.locator(
"[aria-label='Delete Project " + newProjectName + "']"
);

await Promise.all([
deleteButton.click(),
page.waitForResponse(
async (response) =>
response.url().includes('/projects') &&
response.request().method() === 'DELETE' &&
response.status() === 204
),
]);
await expect(page.getByTestId('project_table')).not.toContainText(
newProjectName
);
});

// Create new project with new Client

// Create new project with existing Client

// Delete project via More Options

// Test that project task count is displayed correctly

// Test that active / archive / all filter works (once implemented)
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.7",
"axios": "^1.6.4",
"eslint-plugin-unused-imports": "^3.1.0",
"laravel-vite-plugin": "^1.0.0",
"openapi-zod-client": "^1.16.2",
"postcss": "^8.4.14",
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Components/Common/Client/ClientTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const createClient = ref(false);
<div class="inline-block min-w-full align-middle">
<div
data-testid="client_table"
class="grid min-w-full divide-y divide-row-separator border-b border-row-separator"
class="grid min-w-full"
style="grid-template-columns: 1fr 150px 80px">
<ClientTableHeading></ClientTableHeading>
<div
Expand Down
28 changes: 15 additions & 13 deletions resources/js/Components/Common/Client/ClientTableHeading.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import TableHeading from '@/Components/Common/TableHeading.vue';
</script>

<template>
<div
class="py-1.5 pr-3 text-left text-sm font-semibold text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12 bg-row-heading-background border-t border-row-heading-border">
Name
</div>
<div
class="px-3 py-1.5 text-left text-sm font-semibold text-white bg-row-heading-background">
Status
</div>
<div
class="relative py-1.5 pl-3 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12 bg-row-heading-background">
<span class="sr-only">Edit</span>
</div>
<TableHeading>
<div
class="py-1.5 pr-3 text-left text-sm font-semibold text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12">
Name
</div>
<div class="px-3 py-1.5 text-left text-sm font-semibold text-white">
Status
</div>
<div class="relative py-1.5 pl-3 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12">
<span class="sr-only">Edit</span>
</div>
</TableHeading>
</template>

<style scoped></style>
39 changes: 21 additions & 18 deletions resources/js/Components/Common/Client/ClientTableRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useClientsStore } from '@/utils/useClients';
import { storeToRefs } from 'pinia';
import ClientMoreOptionsDropdown from '@/Components/Common/Client/ClientMoreOptionsDropdown.vue';
import { useProjectsStore } from '@/utils/useProjects';
import TableRow from '@/Components/TableRow.vue';
const { projects } = storeToRefs(useProjectsStore());
Expand All @@ -25,24 +26,26 @@ const projectCount = computed(() => {
</script>

<template>
<div
class="whitespace-nowrap flex items-center space-x-5 3xl:pl-12 py-4 pr-3 text-sm font-medium text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12">
<span>
{{ client.name }}
</span>
<span class="text-muted"> {{ projectCount }} Projects </span>
</div>
<div
class="whitespace-nowrap px-3 py-4 text-sm text-muted flex space-x-1 items-center font-medium">
<CheckCircleIcon class="w-5"></CheckCircleIcon>
<span>Active</span>
</div>
<div
class="relative whitespace-nowrap flex items-center pl-3 text-right text-sm font-medium sm:pr-0 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12">
<ClientMoreOptionsDropdown
:client="client"
@delete="deleteClient"></ClientMoreOptionsDropdown>
</div>
<TableRow>
<div
class="whitespace-nowrap flex items-center space-x-5 3xl:pl-12 py-4 pr-3 text-sm font-medium text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12">
<span>
{{ client.name }}
</span>
<span class="text-muted"> {{ projectCount }} Projects </span>
</div>
<div
class="whitespace-nowrap px-3 py-4 text-sm text-muted flex space-x-1 items-center font-medium">
<CheckCircleIcon class="w-5"></CheckCircleIcon>
<span>Active</span>
</div>
<div
class="relative whitespace-nowrap flex items-center pl-3 text-right text-sm font-medium sm:pr-0 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12">
<ClientMoreOptionsDropdown
:client="client"
@delete="deleteClient"></ClientMoreOptionsDropdown>
</div>
</TableRow>
</template>

<style scoped></style>
2 changes: 1 addition & 1 deletion resources/js/Components/Common/Member/MemberTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const createClient = ref(false);
<div class="inline-block min-w-full align-middle">
<div
data-testid="client_table"
class="grid min-w-full divide-y divide-row-separator border-b border-row-separator"
class="grid min-w-full"
style="grid-template-columns: 1fr 1fr 180px 180px 150px 80px">
<MemberTableHeading></MemberTableHeading>
<template v-for="member in members" :key="member.id">
Expand Down
50 changes: 25 additions & 25 deletions resources/js/Components/Common/Member/MemberTableHeading.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import TableHeading from '@/Components/Common/TableHeading.vue';
</script>

<template>
<div
class="py-1.5 pr-3 text-left text-sm font-semibold text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12 bg-row-heading-background border-t border-row-heading-border">
Name
</div>
<div
class="px-3 py-1.5 text-left text-sm font-semibold text-white bg-row-heading-background">
Email
</div>
<div
class="px-3 py-1.5 text-left text-sm font-semibold text-white bg-row-heading-background">
Role
</div>
<div
class="px-3 py-1.5 text-left text-sm font-semibold text-white bg-row-heading-background">
Billable Rate
</div>
<div
class="px-3 py-1.5 text-left text-sm font-semibold text-white bg-row-heading-background">
Status
</div>
<div
class="relative py-1.5 pl-3 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12 bg-row-heading-background">
<span class="sr-only">Edit</span>
</div>
<TableHeading>
<div
class="py-1.5 pr-3 text-left text-sm font-semibold text-white pl-4 sm:pl-6 lg:pl-8 3xl:pl-12">
Name
</div>
<div class="px-3 py-1.5 text-left text-sm font-semibold text-white">
Email
</div>
<div class="px-3 py-1.5 text-left text-sm font-semibold text-white">
Role
</div>
<div class="px-3 py-1.5 text-left text-sm font-semibold text-white">
Billable Rate
</div>
<div class="px-3 py-1.5 text-left text-sm font-semibold text-white">
Status
</div>
<div
class="relative py-1.5 pl-3 pr-4 sm:pr-6 lg:pr-8 3xl:pr-12 bg-row-heading-background">
<span class="sr-only">Edit</span>
</div>
</TableHeading>
</template>

<style scoped></style>
Loading

0 comments on commit 0ef6d63

Please sign in to comment.