|
| 1 | +import { |
| 2 | + contains, |
| 3 | + field, |
| 4 | + Component, |
| 5 | + FieldDef, |
| 6 | + StringField, |
| 7 | +} from 'https://cardstack.com/base/card-api'; |
| 8 | +import { LooseGooseyField, LooseyGooseyData } from './loosey-goosey'; |
| 9 | +import { PhoneInput, Pill } from '@cardstack/boxel-ui/components'; |
| 10 | +import { RadioInput } from '@cardstack/boxel-ui/components'; |
| 11 | +import { EntityDisplay } from './components/entity-display'; |
| 12 | +import { tracked } from '@glimmer/tracking'; |
| 13 | +import { fn } from '@ember/helper'; |
| 14 | +import { action } from '@ember/object'; |
| 15 | +import PhoneIcon from '@cardstack/boxel-icons/phone'; |
| 16 | + |
| 17 | +class PhoneNumberTypeEdit extends Component<typeof PhoneNumberType> { |
| 18 | + @tracked label: string | undefined = this.args.model.label; |
| 19 | + |
| 20 | + get types() { |
| 21 | + return PhoneNumberType.values; |
| 22 | + } |
| 23 | + |
| 24 | + get selected() { |
| 25 | + return this.types?.find((type) => { |
| 26 | + return type.label === this.label; |
| 27 | + }); |
| 28 | + } |
| 29 | + |
| 30 | + @action onSelect(type: LooseyGooseyData): void { |
| 31 | + this.label = type.label; |
| 32 | + this.args.model.label = this.selected?.label; |
| 33 | + this.args.model.index = this.selected?.index; |
| 34 | + } |
| 35 | + <template> |
| 36 | + <RadioInput |
| 37 | + @groupDescription='Office, Work, Home ' |
| 38 | + @items={{this.types}} |
| 39 | + @checkedId={{this.selected.label}} |
| 40 | + @orientation='horizontal' |
| 41 | + @spacing='default' |
| 42 | + @keyName='label' |
| 43 | + as |item| |
| 44 | + > |
| 45 | + <item.component @onChange={{fn this.onSelect item.data}}> |
| 46 | + {{item.data.label}} |
| 47 | + </item.component> |
| 48 | + </RadioInput> |
| 49 | + </template> |
| 50 | +} |
| 51 | + |
| 52 | +export class PhoneNumberType extends LooseGooseyField { |
| 53 | + static displayName = 'Phone Number Type'; |
| 54 | + static values = [ |
| 55 | + { index: 0, label: 'Mobile' }, |
| 56 | + { index: 1, label: 'Home' }, |
| 57 | + { index: 2, label: 'Work' }, |
| 58 | + ]; |
| 59 | + static edit = PhoneNumberTypeEdit; |
| 60 | +} |
| 61 | + |
| 62 | +export class PhoneField extends FieldDef { |
| 63 | + static displayName = 'Phone Number'; |
| 64 | + @field number = contains(StringField); |
| 65 | + @field countryCode = contains(StringField); |
| 66 | + |
| 67 | + setNumber = (number: string) => { |
| 68 | + this.number = number; |
| 69 | + }; |
| 70 | + |
| 71 | + setCountryCode = (code: string) => { |
| 72 | + this.countryCode = code; |
| 73 | + }; |
| 74 | + |
| 75 | + static edit = class Edit extends Component<typeof PhoneField> { |
| 76 | + <template> |
| 77 | + <PhoneInput |
| 78 | + @countryCode={{@model.countryCode}} |
| 79 | + @value={{@model.number}} |
| 80 | + @onInput={{@model.setNumber}} |
| 81 | + @onCountryCodeChange={{@model.setCountryCode}} |
| 82 | + /> |
| 83 | + </template> |
| 84 | + }; |
| 85 | + |
| 86 | + static atom = class Atom extends Component<typeof PhoneField> { |
| 87 | + <template> |
| 88 | + <EntityDisplay @underline={{false}}> |
| 89 | + <:title> |
| 90 | + {{#if @model.countryCode}} |
| 91 | + +{{@model.countryCode}}{{@model.number}} |
| 92 | + {{else}} |
| 93 | + {{@model.number}} |
| 94 | + {{/if}} |
| 95 | + </:title> |
| 96 | + <:thumbnail> |
| 97 | + <PhoneIcon class='icon' /> |
| 98 | + </:thumbnail> |
| 99 | + </EntityDisplay> |
| 100 | + <style scoped> |
| 101 | + .icon { |
| 102 | + color: var(--boxel-400); |
| 103 | + } |
| 104 | + </style> |
| 105 | + </template> |
| 106 | + }; |
| 107 | + |
| 108 | + static embedded = class Embedded extends Component<typeof PhoneField> { |
| 109 | + <template> |
| 110 | + {{#if @model.countryCode}} |
| 111 | + <span>+{{@model.countryCode}}{{@model.number}}</span> |
| 112 | + {{else}} |
| 113 | + <span>{{@model.number}}</span> |
| 114 | + {{/if}} |
| 115 | + </template> |
| 116 | + }; |
| 117 | +} |
| 118 | + |
| 119 | +export class ContactPhoneNumber extends FieldDef { |
| 120 | + @field phoneNumber = contains(PhoneField); |
| 121 | + @field type = contains(PhoneNumberType); |
| 122 | + |
| 123 | + static atom = class Atom extends Component<typeof ContactPhoneNumber> { |
| 124 | + <template> |
| 125 | + <EntityDisplay @underline={{false}}> |
| 126 | + <:title> |
| 127 | + {{#if @model.phoneNumber.countryCode}} |
| 128 | + +{{@model.phoneNumber.countryCode}}{{@model.phoneNumber.number}} |
| 129 | + {{else}} |
| 130 | + {{@model.phoneNumber.number}} |
| 131 | + {{/if}} |
| 132 | + </:title> |
| 133 | + <:thumbnail> |
| 134 | + <PhoneIcon class='icon' /> |
| 135 | + </:thumbnail> |
| 136 | + <:tag> |
| 137 | + {{#if @model.type.label}} |
| 138 | + <Pill class='pill-gray'> |
| 139 | + {{@model.type.label}} |
| 140 | + </Pill> |
| 141 | + {{/if}} |
| 142 | + </:tag> |
| 143 | + </EntityDisplay> |
| 144 | + <style scoped> |
| 145 | + .icon { |
| 146 | + color: var(--boxel-400); |
| 147 | + } |
| 148 | + .pill-gray { |
| 149 | + --default-pill-padding: 0 var(--boxel-sp-xxxs); |
| 150 | + background-color: var(--boxel-200); |
| 151 | + border-color: transparent; |
| 152 | + } |
| 153 | + </style> |
| 154 | + </template> |
| 155 | + }; |
| 156 | + |
| 157 | + static embedded = class Embedded extends Component< |
| 158 | + typeof ContactPhoneNumber |
| 159 | + > { |
| 160 | + <template> |
| 161 | + <@fields.phoneNumber @format='embedded' /> |
| 162 | + </template> |
| 163 | + }; |
| 164 | +} |
0 commit comments