Fix columns & cards

This commit is contained in:
Brieuc Dubois 2024-01-09 01:25:53 +01:00
parent fb70658f23
commit 5fa653f401
6 changed files with 130 additions and 69 deletions

View File

@ -1,9 +1,8 @@
<script lang="ts"> <script lang="ts">
import currentDraggedCard from '$lib/stores/currentDraggedCard'; import currentDraggedCard from '$lib/stores/currentDraggedCard';
import currentModalCard from '$lib/stores/currentModalCard'; import currentModalCard from '$lib/stores/currentModalCard';
import project_tags from '$lib/stores/projectTags';
import type Card from '$lib/types/Card'; import type Card from '$lib/types/Card';
import ModalCard from './ModalCard.svelte'; // import ModalCard from './ModalCard.svelte';
export let card: Card; export let card: Card;
</script> </script>
@ -21,25 +20,21 @@
} }
}} }}
> >
<div class="title">{card.title}</div> <div class="title">{card.id} - {card.title}</div>
{#if card.tags}
<div class="tags"> <div class="tags">
{#each card.tags as tag} {#each card.cardTags as tag}
{#if tag.option_id} {#if tag.option}
{#if $project_tags[tag.tag_id]} <span class="tag" style="border: 1px solid #333"
<span class="tag" style="border: 1px solid #333"> >{tag.projectTag.id}: {tag.option.id} ({tag.option.value})</span
{$project_tags[tag.tag_id]?.options.find((o) => o.id == tag.option_id)?.value}</span
> >
{/if}
{:else if tag.value} {:else if tag.value}
<span class="tag" style="border: 1px solid #333">{tag.value}</span> <span class="tag" style="border: 1px solid #333">{tag.value}</span>
{/if} {/if}
{/each} {/each}
</div> </div>
{/if}
</div> </div>
<ModalCard bind:card /> <!-- <ModalCard bind:card /> -->
<style lang="less"> <style lang="less">
.card { .card {

View File

@ -1,39 +1,43 @@
<script lang="ts"> <script lang="ts">
import Card from '$lib/types/Card'; import Card, { cards } from '$lib/types/Card';
import CardComponent from '../card/Card.svelte'; import CardComponent from '../card/Card.svelte';
import AddIcon from '../icons/AddIcon.svelte'; import AddIcon from '../icons/AddIcon.svelte';
import type TagOption from '$lib/types/TagOption'; import type TagOption from '$lib/types/TagOption';
import type ProjectTag from '$lib/types/ProjectTag'; import type ProjectTag from '$lib/types/ProjectTag';
import type Project from '$lib/types/Project'; import type Project from '$lib/types/Project';
import currentDraggedCard from '$lib/stores/currentDraggedCard';
export let project: Project; export let project: Project;
export let option: TagOption | null = null; export let option: TagOption | null = null;
export let primaryTag: ProjectTag | null = null; export let primaryTag: ProjectTag | null = null;
export let title: string;
export let columnCards: Card[] = []; export let columnCards: Card[] = [];
let lastTitle = title; let newOptionValue = option?.value || `No ${primaryTag?.title}`;
// async function onDrop(e: DragEvent) { async function onDrop(e: DragEvent) {
// e.preventDefault(); e.preventDefault();
// if (!$currentDraggedCard || !$currentDraggedCard.cardTags) return; if (!primaryTag || !$currentDraggedCard || !$currentDraggedCard.cardTags) return;
// $currentDraggedCard; const currentCardTag =
$currentDraggedCard.cardTags.find((tag) => tag.projectTag === primaryTag) || null;
const currentOption = currentCardTag?.option || null;
// for (let tag of $currentDraggedCard.cardTags) { if (currentOption === option) return;
// if (tag.projectTag !== primaryTag) continue;
// if (tag.option == option) return;
// if (!tag.option && !tag.value) await tag.delete(); if (!currentOption && option) {
// else if (tag.option && optionId) await $currentDraggedCard.addTag(primaryTag, option, null);
// await createCardTagApi(tag.card_id, tag.tag_id, tag.option_id, tag.value); } else if (currentOption && !option) {
// else await updateCardTagApi(tag.card_id, tag.tag_id, optionId, tag.value); if (!currentCardTag) return;
await $currentDraggedCard.removeTag(currentCardTag);
} else if (currentOption && option) {
if (!currentCardTag) return;
await $currentDraggedCard.updateTag(currentCardTag, option, null);
}
// tag.option_id = optionId; currentDraggedCard.set(null);
// cards.reload();
// } cards.reload();
// currentDraggedCard.set(null); }
// }
async function addCard() { async function addCard() {
const card = await Card.create(project); const card = await Card.create(project);
@ -43,33 +47,30 @@
if (!option) return; if (!option) return;
await card.addTag(primaryTag, option, null); await card.addTag(primaryTag, option, null);
cards.reload();
} }
</script> </script>
<!-- on:drop={onDrop} -->
<div <div
class="column" class="column"
role="listbox" role="listbox"
tabindex="-1" tabindex="-1"
on:drop={onDrop}
on:dragover={(e) => { on:dragover={(e) => {
e.preventDefault(); e.preventDefault();
}} }}
> >
<header> <header>
<input <input
bind:value={title} bind:value={newOptionValue}
type="text" type="text"
on:blur={async () => { on:blur={async () => {
if (lastTitle === title) return;
if (!option || !primaryTag) return; if (!option || !primaryTag) return;
// option; if (newOptionValue === option.value) return;
// await updateTagOptionAPI({
// id: optionId, await option.setValue(newOptionValue);
// tag_id: primary_tag_id, newOptionValue = option.value;
// value: title
// });
// lastTitle = title;
// cards.reload();
}} }}
disabled={option === null} disabled={option === null}
/> />

View File

@ -6,21 +6,22 @@
import Header from './Header.svelte'; import Header from './Header.svelte';
export let project: Project; export let project: Project;
$: allCards = $cards;
</script> </script>
{#if project} {#if project}
<section> <section>
{#if $currentView} {#if $currentView}
<Header {project} /> <Header {project} />
{#if $cards} {#if $cards && allCards}
<div class="grid"> <div class="grid">
{#if $currentView.primaryTag} {#if $currentView.primaryTag}
{#each $currentView.primaryTag.options as option} {#each $currentView.primaryTag.options as option}
<Column <Column
{option} {option}
primaryTag={$currentView.primaryTag} primaryTag={$currentView.primaryTag}
title={option.value} columnCards={allCards
columnCards={$cards
.filter((c) => c.cardTags.map((t) => t.option).includes(option)) .filter((c) => c.cardTags.map((t) => t.option).includes(option))
.sort((a, b) => { .sort((a, b) => {
if (!$currentView?.sortTag) return 0; if (!$currentView?.sortTag) return 0;
@ -43,15 +44,14 @@
{/if} {/if}
<Column <Column
primaryTag={$currentView.primaryTag} primaryTag={$currentView.primaryTag}
title={$currentView.primaryTag ? `No ${$currentView.title}` : 'No groups'}
columnCards={$currentView.primaryTag != null columnCards={$currentView.primaryTag != null
? (() => { ? (() => {
const primaryTag = $currentView.primaryTag; const primaryTag = $currentView.primaryTag;
return $cards.filter( return allCards.filter(
(c) => !c.cardTags.map((t) => t.projectTag).includes(primaryTag) (c) => !c.cardTags.map((t) => t.projectTag).includes(primaryTag)
); );
})() })()
: $cards} : allCards}
{project} {project}
/> />
</div> </div>

View File

@ -6,7 +6,14 @@ import { toastAlert } from '$lib/utils/toasts';
import type TagOption from './TagOption'; import type TagOption from './TagOption';
import type ProjectTag from './ProjectTag'; import type ProjectTag from './ProjectTag';
export const cards = writable([] as Card[]); const { subscribe, set, update } = writable([] as Card[]);
export const cards = {
subscribe,
set,
update,
reload: () => update((cards) => cards)
};
export default class Card { export default class Card {
private _id: number; private _id: number;
@ -90,16 +97,35 @@ export default class Card {
if (!cardTag) return false; if (!cardTag) return false;
this._cardTags.push(cardTag); this._cardTags = [...this._cardTags, cardTag];
return true; return true;
} }
async removeTag(cardTag: CardTag): Promise<boolean> {
const res = await cardTag.delete();
if (!res) return false;
this._cardTags = this._cardTags.filter((ct) => ct !== cardTag);
return true;
}
async updateTag(
cardTag: CardTag,
tagOption: TagOption | null,
value: string | null
): Promise<boolean> {
return await cardTag.update(tagOption, value);
}
static parse(json: any): Card | null; static parse(json: any): Card | null;
static parse(json: any, project: Project | null | undefined): Card | null; static parse(json: any, project: Project | null | undefined): Card | null;
static parse(json: any, project?: Project | null | undefined): Card | null { static parse(json: any, project?: Project | null | undefined): Card | null {
if (json === null) { if (json === null) {
toastAlert('Failed to parse card: json is null');
return null; return null;
} }

View File

@ -1,4 +1,5 @@
import cardsTagsApi from '$lib/api/cardsTagsApi'; import cardsTagsApi from '$lib/api/cardsTagsApi';
import { toastAlert } from '$lib/utils/toasts';
import Card from './Card'; import Card from './Card';
import ProjectTag from './ProjectTag'; import ProjectTag from './ProjectTag';
import TagOption from './TagOption'; import TagOption from './TagOption';
@ -21,16 +22,16 @@ export default class CardTag {
this._value = value; this._value = value;
} }
get card(): number { get card(): Card {
return this.card; return this._card;
} }
get projectTag(): ProjectTag { get projectTag(): ProjectTag {
return this.projectTag; return this._projectTag;
} }
get option(): TagOption | null { get option(): TagOption | null {
return this.option; return this._option;
} }
get value(): string | null { get value(): string | null {
@ -43,31 +44,58 @@ export default class CardTag {
option: TagOption | null, option: TagOption | null,
value: string | null value: string | null
): Promise<CardTag | null> { ): Promise<CardTag | null> {
const id = await cardsTagsApi.create(card.id, tag.id, option ? option.id : null, value); const res = await cardsTagsApi.create(card.id, tag.id, option ? option.id : null, value);
if (!id) return null; if (!res) return null;
return new CardTag(card, tag, option, value); return new CardTag(card, tag, option, value);
} }
async delete() { async delete(): Promise<boolean> {
return cardsTagsApi.delete(this._card.id, this._projectTag.id); return cardsTagsApi.delete(this._card.id, this._projectTag.id);
} }
async update(option: TagOption | null, value: string | null): Promise<boolean> {
const res = await cardsTagsApi.update(
this._card.id,
this._projectTag.id,
option ? option.id : null,
value
);
if (!res) return false;
this._option = option;
this._value = value;
return true;
}
static parse(json: any): CardTag | null; static parse(json: any): CardTag | null;
static parse(json: any, card: Card | null | undefined): CardTag | null; static parse(json: any, card: Card | null | undefined): CardTag | null;
static parse(json: any, card?: Card | null | undefined): CardTag | null { static parse(json: any, card?: Card | null | undefined): CardTag | null {
if (!json) return null; if (!json) {
toastAlert('Failed to parse card tag: json is null');
return null;
}
if (!card) card = Card.fromId(json.card_id); if (!card) card = Card.fromId(json.card_id);
if (!card) return null; if (!card) {
toastAlert('Failed to parse card tag: card is null');
return null;
}
const tag = ProjectTag.fromId(json.tag_id); const tag = ProjectTag.fromId(json.tag_id);
if (!tag) return null; if (!tag) {
toastAlert('Failed to parse card tag: tag is null');
return null;
}
const option = tag.options.find((option) => option.id === json.option_id); const option = tag.options.find((option) => option.id === json.option_id);
if (!option) return null; if (!option) {
toastAlert('Failed to parse card tag: option is null');
return null;
}
return new CardTag(card, tag, option, json.value); return new CardTag(card, tag, option, json.value);
} }

View File

@ -1,3 +1,4 @@
import tagsOptions from '$lib/api/tagsOptions';
import ProjectTag from './ProjectTag'; import ProjectTag from './ProjectTag';
export default class TagOption { export default class TagOption {
@ -23,6 +24,16 @@ export default class TagOption {
return this._value; return this._value;
} }
async setValue(value: string): Promise<boolean> {
const res = await tagsOptions.update(this._id, this.projectTag.id, value);
if (!res) return false;
this._value = value;
return res;
}
static parse(json: any): TagOption | null; static parse(json: any): TagOption | null;
static parse(json: any, projectTag: ProjectTag | null | undefined): TagOption | null; static parse(json: any, projectTag: ProjectTag | null | undefined): TagOption | null;