Reformat cards
This commit is contained in:
parent
4ca04b8cc8
commit
10b11f10dd
|
@ -4,5 +4,10 @@
|
|||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
"overrides": [
|
||||
{ "files": "*.svelte", "options": { "parser": "svelte" } },
|
||||
{ "files": "*.ts", "options": { "parser": "typescript" } },
|
||||
{ "files": "*.js", "options": { "parser": "babel" } },
|
||||
{ "files": "*.css", "options": { "parser": "css" } }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import type { Card } from '../stores/interfaces';
|
||||
import api, { processError } from '../utils/api';
|
||||
import status from '../utils/status';
|
||||
|
||||
export async function newCardApi(projectId: number): Promise<Card> {
|
||||
const response = await api.post(`/v1/cards`, {
|
||||
project_id: projectId,
|
||||
title: 'Untitled',
|
||||
content: ''
|
||||
});
|
||||
|
||||
if (response.status !== status.Created) {
|
||||
processError(response, 'Failed to create card');
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
const id: number = response.data.id;
|
||||
|
||||
return {
|
||||
id: id,
|
||||
project_id: projectId,
|
||||
title: 'Untitled',
|
||||
content: '',
|
||||
tags: []
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteCardApi(cardID: number): Promise<void> {
|
||||
const response = await api.delete(`/v2/cards/${cardID}`);
|
||||
|
||||
if (response.status !== status.NoContent) {
|
||||
processError(response, 'Failed to delete card');
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { parseCards, type Card, type Project } from '../stores/interfaces';
|
||||
import api, { processError } from '../utils/api';
|
||||
import status from '../utils/status';
|
||||
|
||||
export async function getProjectAPI(projectId: number): Promise<Project> {
|
||||
const response = await api.get(`/v1/projects/${projectId}`);
|
||||
|
||||
if (response.status !== status.OK) {
|
||||
processError(response, 'Failed to fetch project');
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getProjectCardsAPI(projectId: number): Promise<Card[]> {
|
||||
const response = await api.get(`/v1/projects/${projectId}/cards`);
|
||||
|
||||
if (response.status !== status.OK) {
|
||||
processError(response, 'Failed to fetch cards');
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return parseCards(response.data);
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
<script lang="ts">
|
||||
import currentModalCard from '../stores/currentModalCard';
|
||||
import type { Card } from '../stores/interfaces';
|
||||
import projectTags from '../stores/projectTags';
|
||||
import ModalCard from './modal_card.svelte';
|
||||
|
||||
export let card: Card;
|
||||
export let showModal: boolean;
|
||||
let showModal: boolean = $currentModalCard == card.id;
|
||||
export let onDelete: () => void;
|
||||
|
||||
function editCard() {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">
|
||||
import type { Card, TagOption } from '../stores/interfaces';
|
||||
import CardC from './card.svelte';
|
||||
|
||||
export let tag_id: number;
|
||||
export let option: TagOption;
|
||||
export let cards: Card[] = [];
|
||||
export let deleteCard: (id: number) => void;
|
||||
|
||||
let columnCards = cards.filter(
|
||||
(card) => card.tags.find((t) => t.tag_id === tag_id)?.option_id === option.id
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="column">
|
||||
<h3>{option.value}</h3>
|
||||
<ul>
|
||||
{#each columnCards as card}
|
||||
<CardC {card} onDelete={async () => await deleteCard(card.id)} />
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.column {
|
||||
width: 200px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
</style>
|
|
@ -2,105 +2,75 @@
|
|||
import { onMount } from 'svelte';
|
||||
import CardC from './card.svelte';
|
||||
import { type Project, type Card, parseCards, type View } from '../stores/interfaces';
|
||||
import status from '../utils/status';
|
||||
import api, { processError } from '../utils/api';
|
||||
import projectTags from '../stores/projectTags';
|
||||
import currentView from '../stores/currentView';
|
||||
import Card from './card.svelte';
|
||||
import { deleteCardApi, newCardApi } from '../api/cards';
|
||||
import { getProjectAPI, getProjectCardsAPI } from '../api/projects';
|
||||
import Column from './column.svelte';
|
||||
import currentModalCard from '../stores/currentModalCard';
|
||||
|
||||
export let projectId: number;
|
||||
|
||||
let project: Project;
|
||||
let cards: Card[];
|
||||
let cards: Card[] = [];
|
||||
let view: View | null = null;
|
||||
let columns: { id: number; title: string; cards: Card[] }[] = [];
|
||||
|
||||
onMount(async () => {
|
||||
let response = await api.get(`/v1/projects/${projectId}`);
|
||||
getProjectAPI(projectId).then((p) => {
|
||||
project = p;
|
||||
});
|
||||
|
||||
if (response.status !== status.OK) {
|
||||
processError(response, 'Failed to fetch project');
|
||||
return;
|
||||
}
|
||||
|
||||
project = response.data;
|
||||
|
||||
response = await api.get(`/v1/projects/${projectId}/cards`);
|
||||
|
||||
if (response.status === status.OK) {
|
||||
cards = parseCards(response.data);
|
||||
} else {
|
||||
cards = [];
|
||||
processError(response, 'Failed to fetch cards');
|
||||
return;
|
||||
}
|
||||
getProjectCardsAPI(projectId).then((c) => {
|
||||
cards = parseCards(c);
|
||||
loadColumns();
|
||||
});
|
||||
|
||||
if (!(await projectTags.init(projectId))) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
let modalID = -1;
|
||||
|
||||
async function newCard() {
|
||||
const response = await api.post(`/v1/cards`, {
|
||||
project_id: projectId,
|
||||
title: 'Untitled',
|
||||
content: ''
|
||||
});
|
||||
|
||||
if (response.status !== status.Created) {
|
||||
processError(response, 'Failed to create card');
|
||||
return;
|
||||
}
|
||||
|
||||
const id: number = response.data.id;
|
||||
|
||||
let card: Card = {
|
||||
id: id,
|
||||
project_id: projectId,
|
||||
title: 'Untitled',
|
||||
content: '',
|
||||
tags: []
|
||||
};
|
||||
|
||||
cards = [...cards, card];
|
||||
modalID = id;
|
||||
}
|
||||
|
||||
async function deleteCard(cardID: number) {
|
||||
const response = await api.delete(`/v2/cards/${cardID}`);
|
||||
|
||||
if (response.status !== status.NoContent) {
|
||||
processError(response, 'Failed to delete card');
|
||||
return;
|
||||
}
|
||||
|
||||
cards = cards.filter((card) => card.id !== cardID);
|
||||
}
|
||||
|
||||
let view: View | null = null;
|
||||
let columns: { id: number; title: string; cards: Card[] }[] = [];
|
||||
|
||||
currentView.subscribe((v) => {
|
||||
view = v;
|
||||
if (!v) return;
|
||||
let primary_tag_id = v.primary_tag_id;
|
||||
columns = $projectTags[primary_tag_id].options.map((o) => {
|
||||
loadColumns();
|
||||
});
|
||||
});
|
||||
|
||||
function newCard() {
|
||||
newCardApi(projectId).then((card) => {
|
||||
cards = [...cards, card];
|
||||
currentModalCard.set(card.id);
|
||||
loadColumns();
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCard(id: number) {
|
||||
deleteCardApi(id).then(() => {
|
||||
cards = cards.filter((card) => card.id !== id);
|
||||
loadColumns();
|
||||
});
|
||||
}
|
||||
|
||||
function loadColumns() {
|
||||
if (!view) return;
|
||||
let primary_tag_id = view.primary_tag_id;
|
||||
columns =
|
||||
$projectTags[primary_tag_id]?.options.map((o) => {
|
||||
return {
|
||||
id: o.id,
|
||||
title: o.value,
|
||||
cards: cards.filter((c) => c.tags.map((t) => t.option_id).includes(o.id))
|
||||
};
|
||||
});
|
||||
}) || [];
|
||||
columns.push({
|
||||
id: -1,
|
||||
title: 'No tag',
|
||||
cards: cards.filter((c) => {
|
||||
const tag = c.tags.find((t) => t.tag_id === primary_tag_id);
|
||||
|
||||
return tag?.option_id == -1;
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -115,25 +85,14 @@
|
|||
<h2>{project.title}</h2>
|
||||
<button on:click={newCard}>New card</button>
|
||||
</header>
|
||||
{#if view}
|
||||
{#if view && $projectTags[view.primary_tag_id]}
|
||||
<div class="grid">
|
||||
{#each columns as column}
|
||||
<div class="column">
|
||||
<h3>{column.title}</h3>
|
||||
<ul>
|
||||
{#each column.cards as card}
|
||||
<CardC
|
||||
{card}
|
||||
showModal={modalID === card.id}
|
||||
onDelete={async () => await deleteCard(card.id)}
|
||||
/>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{#each $projectTags[view.primary_tag_id].options as option}
|
||||
<Column tag_id={view.primary_tag_id} {option} bind:cards deleteCard />
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<ul>
|
||||
<!-- <ul>
|
||||
{#if cards}
|
||||
{#each cards as card}
|
||||
<CardC
|
||||
|
@ -143,7 +102,7 @@
|
|||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
</ul> -->
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
}
|
||||
|
||||
views = response.data;
|
||||
|
||||
if (views.length > 0) currentView.set(views[0]);
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<link rel="stylesheet" type="text/css" href="/css/sidebar.css" />
|
||||
</svelte:head>
|
||||
|
||||
<div id="sidebar" class="sidebar">
|
||||
<div class="logo">
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import { writable } from 'svelte/store';
|
||||
|
||||
export default writable(-1);
|
Loading…
Reference in New Issue