@@ -21,6 +21,7 @@ import { LooseGooseyField, type LooseyGooseyData } from './loosey-goosey';
21
21
import { tracked } from ' @glimmer/tracking' ;
22
22
import { action } from ' @ember/object' ;
23
23
import { fn } from ' @ember/helper' ;
24
+
24
25
import ChevronsUp from ' @cardstack/boxel-icons/chevrons-up' ;
25
26
import ChevronUp from ' @cardstack/boxel-icons/chevron-up' ;
26
27
import ChevronsDown from ' @cardstack/boxel-icons/chevrons-down' ;
@@ -29,6 +30,11 @@ import CircleEqual from '@cardstack/boxel-icons/circle-equal';
29
30
import { isToday , isThisWeek , addWeeks } from ' date-fns' ;
30
31
import GlimmerComponent from ' @glimmer/component' ;
31
32
import Calendar from ' @cardstack/boxel-icons/calendar' ;
33
+ import { isToday , isThisWeek , addWeeks } from ' date-fns' ;
34
+ import GlimmerComponent from ' @glimmer/component' ;
35
+ import Calendar from ' @cardstack/boxel-icons/calendar' ;
36
+ import ChevronsUp from ' @cardstack/boxel-icons/chevrons-up' ;
37
+
32
38
import { Pill } from ' @cardstack/boxel-ui/components' ;
33
39
import { CheckMark } from ' @cardstack/boxel-ui/icons' ;
34
40
@@ -148,6 +154,7 @@ export class FittedTask extends Component<typeof TaskBase> {
148
154
</div >
149
155
<div class =' short-id-container' >
150
156
<@ fields.priority @ format =' atom' />
157
+ <ChevronsUp width =' 14px' height =' 14px' />
151
158
<span class =' short-id' >{{@ model.shortId }} </span >
152
159
</div >
153
160
</header >
@@ -650,3 +657,125 @@ export class TaskCompletionStatus extends GlimmerComponent<TaskCompletionStatusS
650
657
< /style >
651
658
</template >
652
659
}
660
+
661
+ export class TaskBase extends CardDef {
662
+ static displayName = ' Task Base' ;
663
+ @field taskName = contains (StringField );
664
+ @field tags = linksToMany (() => Tag );
665
+ @field dateRange = contains (DateRangeField );
666
+ @field status = contains (BaseTaskStatusField );
667
+ @field taskDetail = contains (TextAreaCard );
668
+ @field assignee = linksTo (() => User );
669
+ @field priority = contains (BaseTaskPriority );
670
+
671
+ @field title = contains (StringField , {
672
+ computeVia : function (this : TaskBase ) {
673
+ return this .taskName ;
674
+ },
675
+ });
676
+
677
+ @field shortId = contains (StringField , {
678
+ computeVia : function (this : TaskBase ) {
679
+ if (this .id ) {
680
+ let id = shortenId (extractId (this .id ));
681
+ return id .toUpperCase ();
682
+ }
683
+ return ;
684
+ },
685
+ });
686
+
687
+ static fitted = FittedTask ;
688
+ }
689
+
690
+ function extractId(href : string ): string {
691
+ const urlObj = new URL (href );
692
+ const pathname = urlObj .pathname ;
693
+ const parts = pathname .split (' /' );
694
+ const lastPart = parts [parts .length - 1 ];
695
+ return lastPart .replace (' .json' , ' ' );
696
+ }
697
+
698
+ function shortenId(id : string ): string {
699
+ const shortUuid = id .slice (0 , 8 );
700
+ const decimal = parseInt (shortUuid , 16 );
701
+ return decimal .toString (36 ).padStart (6 , ' 0' );
702
+ }
703
+
704
+ function getDueDateStatus(dueDateString : string | null ) {
705
+ if (! dueDateString ) return null ;
706
+
707
+ const dueDate = new Date (dueDateString );
708
+ const today = new Date ();
709
+ const nextWeek = addWeeks (today , 1 );
710
+
711
+ if (isToday (dueDate )) {
712
+ return {
713
+ label: ' Due Today' ,
714
+ color: ' #01de67' ,
715
+ };
716
+ } else if (isThisWeek (dueDate )) {
717
+ return {
718
+ label: ' This Week' ,
719
+ color: ' #ffbc00' ,
720
+ };
721
+ } else if (dueDate > today && dueDate < nextWeek ) {
722
+ return {
723
+ label: ' Next Week' ,
724
+ color: ' #4fc8fd' ,
725
+ };
726
+ }
727
+
728
+ return null ;
729
+ }
730
+
731
+ interface TaskCompletionStatusSignature {
732
+ Element: HTMLDivElement ;
733
+ Args: {
734
+ completed: boolean ;
735
+ };
736
+ }
737
+
738
+ export class TaskCompletionStatus extends GlimmerComponent <TaskCompletionStatusSignature > {
739
+ <template >
740
+ <div class =' completion-status' ...attributes >
741
+ <span class =' checkmark {{if @ completed " completed" }} ' >
742
+ {{#if @ completed }}
743
+ <CheckMark class =' checkmark-icon' />
744
+ {{/if }}
745
+ </span >
746
+ </div >
747
+
748
+ <style scoped >
749
+ .completion-status {
750
+ --circle-size : var (--boxel-circle-size , 20px );
751
+ --border-radius : var (
752
+ --boxel-border-radius ,
753
+ var (--boxel-border-radius-xs )
754
+ );
755
+ display : inline-flex ;
756
+ align-items : center ;
757
+ }
758
+ .checkmark {
759
+ position : relative ;
760
+ display : flex ;
761
+ align-items : center ;
762
+ justify-content : center ;
763
+ height : var (--circle-size );
764
+ width : var (--circle-size );
765
+ background-color : white ;
766
+ border : 2px solid var (--boxel-400 );
767
+ border-radius : var (--border-radius );
768
+ transition : all 0.2s ease ;
769
+ }
770
+ .checkmark.completed {
771
+ background-color : var (--boxel-highlight );
772
+ color : white ;
773
+ }
774
+ .checkmark-icon {
775
+ --icon-size : calc (var (--circle-size , 20px ) * 0.8 );
776
+ width : var (--icon-size );
777
+ height : var (--icon-size );
778
+ }
779
+ < /style >
780
+ </template >
781
+ }
0 commit comments