profile-pane 3.2.1 → 3.2.2-test.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/README.md +50 -0
  2. package/lib/303.profile-pane.js +1362 -0
  3. package/lib/303.profile-pane.js.map +1 -0
  4. package/lib/303.profile-pane.min.js +2 -0
  5. package/lib/303.profile-pane.min.js.map +1 -0
  6. package/lib/ProfileView.css +1090 -0
  7. package/lib/ProfileView.d.ts +2 -1
  8. package/lib/ProfileView.d.ts.map +1 -1
  9. package/lib/ProfileView.js +64 -36
  10. package/lib/buttonsHelper.d.ts +1 -1
  11. package/lib/buttonsHelper.d.ts.map +1 -1
  12. package/lib/buttonsHelper.js +2 -1
  13. package/lib/editProfilePane/EditCVCard.js +1 -1
  14. package/lib/editProfilePane/EditCommunitiesCard.js +1 -1
  15. package/lib/editProfilePane/EditFriendsCard.js +1 -1
  16. package/lib/editProfilePane/EditProfileView.d.ts +1 -1
  17. package/lib/editProfilePane/EditProfileView.d.ts.map +1 -1
  18. package/lib/editProfilePane/EditProfileView.js +4 -5
  19. package/lib/editProfilePane/editProfilePresenter.d.ts.map +1 -1
  20. package/lib/editProfilePane/editProfilePresenter.js +5 -4
  21. package/lib/icons-svg/profileIcons.d.ts +1 -1
  22. package/lib/icons-svg/profileIcons.d.ts.map +1 -1
  23. package/lib/icons-svg/profileIcons.js +9 -17
  24. package/lib/index.d.ts +1 -8
  25. package/lib/index.d.ts.map +1 -1
  26. package/lib/index.js +74 -40
  27. package/lib/ontology/otherPreferencesForm.ttl +32 -0
  28. package/lib/ontology/resumeForm.ttl +349 -0
  29. package/lib/ontology/socialMedia.ttl +433 -0
  30. package/lib/profile-pane.js +32266 -13247
  31. package/lib/profile-pane.js.map +1 -1
  32. package/lib/profile-pane.min.js +2315 -935
  33. package/lib/profile-pane.min.js.map +1 -1
  34. package/lib/rdfFormsHelper.d.ts +13 -1
  35. package/lib/rdfFormsHelper.d.ts.map +1 -1
  36. package/lib/rdfFormsHelper.js +13 -1
  37. package/lib/sections/bio/BioEditDialog.d.ts.map +1 -1
  38. package/lib/sections/bio/BioEditDialog.js +7 -7
  39. package/lib/sections/bio/BioSection.css +300 -0
  40. package/lib/sections/bio/BioSection.d.ts +3 -2
  41. package/lib/sections/bio/BioSection.d.ts.map +1 -1
  42. package/lib/sections/bio/BioSection.js +26 -19
  43. package/lib/sections/bio/mutations.d.ts.map +1 -1
  44. package/lib/sections/bio/mutations.js +14 -3
  45. package/lib/sections/contactInfo/ContactInfoEditDialog.css +354 -0
  46. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts +3 -1
  47. package/lib/sections/contactInfo/ContactInfoEditDialog.d.ts.map +1 -1
  48. package/lib/sections/contactInfo/ContactInfoEditDialog.js +183 -98
  49. package/lib/sections/contactInfo/ContactInfoSection.css +125 -0
  50. package/lib/sections/contactInfo/ContactInfoSection.d.ts +2 -0
  51. package/lib/sections/contactInfo/ContactInfoSection.d.ts.map +1 -1
  52. package/lib/sections/contactInfo/ContactInfoSection.js +64 -41
  53. package/lib/sections/contactInfo/mutations.d.ts.map +1 -1
  54. package/lib/sections/contactInfo/mutations.js +51 -16
  55. package/lib/sections/education/EducationEditDialog.d.ts +3 -1
  56. package/lib/sections/education/EducationEditDialog.d.ts.map +1 -1
  57. package/lib/sections/education/EducationEditDialog.js +170 -92
  58. package/lib/sections/education/EducationSection.css +133 -0
  59. package/lib/sections/education/EducationSection.d.ts +3 -2
  60. package/lib/sections/education/EducationSection.d.ts.map +1 -1
  61. package/lib/sections/education/EducationSection.js +32 -25
  62. package/lib/sections/education/mutations.d.ts.map +1 -1
  63. package/lib/sections/education/mutations.js +14 -3
  64. package/lib/sections/heading/HeadingEditDialog.d.ts +4 -1
  65. package/lib/sections/heading/HeadingEditDialog.d.ts.map +1 -1
  66. package/lib/sections/heading/HeadingEditDialog.js +287 -162
  67. package/lib/sections/heading/HeadingSection.css +862 -0
  68. package/lib/sections/heading/HeadingSection.d.ts +3 -2
  69. package/lib/sections/heading/HeadingSection.d.ts.map +1 -1
  70. package/lib/sections/heading/HeadingSection.js +63 -32
  71. package/lib/sections/heading/imageHelpers.d.ts +1 -0
  72. package/lib/sections/heading/imageHelpers.d.ts.map +1 -1
  73. package/lib/sections/heading/imageHelpers.js +40 -1
  74. package/lib/sections/heading/mutations.d.ts.map +1 -1
  75. package/lib/sections/heading/mutations.js +86 -23
  76. package/lib/sections/heading/selectors.d.ts.map +1 -1
  77. package/lib/sections/heading/selectors.js +14 -3
  78. package/lib/sections/heading/types.d.ts +1 -2
  79. package/lib/sections/heading/types.d.ts.map +1 -1
  80. package/lib/sections/languages/LanguageEditDialog.d.ts +3 -1
  81. package/lib/sections/languages/LanguageEditDialog.d.ts.map +1 -1
  82. package/lib/sections/languages/LanguageEditDialog.js +202 -119
  83. package/lib/sections/languages/LanguageSection.css +53 -0
  84. package/lib/sections/languages/LanguageSection.d.ts +2 -0
  85. package/lib/sections/languages/LanguageSection.d.ts.map +1 -1
  86. package/lib/sections/languages/LanguageSection.js +42 -31
  87. package/lib/sections/languages/mutations.d.ts.map +1 -1
  88. package/lib/sections/languages/mutations.js +60 -161
  89. package/lib/sections/languages/selectors.d.ts.map +1 -1
  90. package/lib/sections/languages/selectors.js +1 -2
  91. package/lib/sections/projects/ProjectEditDialog.d.ts +2 -1
  92. package/lib/sections/projects/ProjectEditDialog.d.ts.map +1 -1
  93. package/lib/sections/projects/ProjectEditDialog.js +13 -24
  94. package/lib/sections/projects/ProjectSection.css +368 -0
  95. package/lib/sections/projects/ProjectSection.d.ts +2 -1
  96. package/lib/sections/projects/ProjectSection.d.ts.map +1 -1
  97. package/lib/sections/projects/ProjectSection.js +116 -34
  98. package/lib/sections/projects/mutations.d.ts.map +1 -1
  99. package/lib/sections/projects/mutations.js +109 -132
  100. package/lib/sections/projects/selectors.d.ts.map +1 -1
  101. package/lib/sections/projects/selectors.js +4 -45
  102. package/lib/{QRCodeCard.d.ts → sections/qrcode/QRCodeCard.d.ts} +2 -1
  103. package/lib/sections/qrcode/QRCodeCard.d.ts.map +1 -0
  104. package/lib/{QRCodeCard.js → sections/qrcode/QRCodeCard.js} +59 -11
  105. package/lib/sections/qrcode/QRCodeSection.css +108 -0
  106. package/lib/sections/qrcode/QRCodeSection.d.ts +4 -0
  107. package/lib/sections/qrcode/QRCodeSection.d.ts.map +1 -0
  108. package/lib/sections/qrcode/QRCodeSection.js +17 -0
  109. package/lib/sections/resume/ResumeEditDialog.d.ts +10 -1
  110. package/lib/sections/resume/ResumeEditDialog.d.ts.map +1 -1
  111. package/lib/sections/resume/ResumeEditDialog.js +531 -149
  112. package/lib/sections/resume/ResumeSection.css +350 -0
  113. package/lib/sections/resume/ResumeSection.d.ts +3 -2
  114. package/lib/sections/resume/ResumeSection.d.ts.map +1 -1
  115. package/lib/sections/resume/ResumeSection.js +78 -49
  116. package/lib/sections/resume/mutations.d.ts.map +1 -1
  117. package/lib/sections/resume/mutations.js +17 -3
  118. package/lib/sections/resume/selectors.d.ts.map +1 -1
  119. package/lib/sections/resume/selectors.js +1 -0
  120. package/lib/sections/resume/types.d.ts +1 -0
  121. package/lib/sections/resume/types.d.ts.map +1 -1
  122. package/lib/sections/shared/collapsibleSection.d.ts.map +1 -1
  123. package/lib/sections/shared/collapsibleSection.js +1 -0
  124. package/lib/sections/shared/phoneCountries.d.ts +1 -1
  125. package/lib/sections/shared/phoneCountries.d.ts.map +1 -1
  126. package/lib/sections/shared/phoneCountries.js +2 -2
  127. package/lib/sections/shared/projectCommunityNodes.d.ts +6 -0
  128. package/lib/sections/shared/projectCommunityNodes.d.ts.map +1 -0
  129. package/lib/sections/shared/projectCommunityNodes.js +56 -0
  130. package/lib/sections/shared/rdfMutationHelpers.d.ts +35 -2
  131. package/lib/sections/shared/rdfMutationHelpers.d.ts.map +1 -1
  132. package/lib/sections/shared/rdfMutationHelpers.js +290 -14
  133. package/lib/sections/shared/sectionCardHelpers.d.ts.map +1 -1
  134. package/lib/sections/shared/sectionCardHelpers.js +80 -11
  135. package/lib/sections/shared/types.d.ts +24 -0
  136. package/lib/sections/shared/types.d.ts.map +1 -1
  137. package/lib/sections/skills/SkillsEditDialog.d.ts +3 -1
  138. package/lib/sections/skills/SkillsEditDialog.d.ts.map +1 -1
  139. package/lib/sections/skills/SkillsEditDialog.js +136 -115
  140. package/lib/sections/skills/SkillsSection.css +173 -0
  141. package/lib/sections/skills/SkillsSection.d.ts +2 -0
  142. package/lib/sections/skills/SkillsSection.d.ts.map +1 -1
  143. package/lib/sections/skills/SkillsSection.js +107 -47
  144. package/lib/sections/skills/mutations.d.ts.map +1 -1
  145. package/lib/sections/skills/mutations.js +25 -21
  146. package/lib/sections/skills/selectors.d.ts.map +1 -1
  147. package/lib/sections/skills/selectors.js +5 -3
  148. package/lib/sections/social/SocialEditDialog.d.ts +3 -1
  149. package/lib/sections/social/SocialEditDialog.d.ts.map +1 -1
  150. package/lib/sections/social/SocialEditDialog.js +170 -62
  151. package/lib/sections/social/SocialSection.css +194 -0
  152. package/lib/sections/social/SocialSection.d.ts +4 -3
  153. package/lib/sections/social/SocialSection.d.ts.map +1 -1
  154. package/lib/sections/social/SocialSection.js +59 -43
  155. package/lib/sections/social/mutations.d.ts.map +1 -1
  156. package/lib/sections/social/mutations.js +23 -132
  157. package/lib/specialButtons/AddMeToYourFriends.css +54 -0
  158. package/lib/specialButtons/addContact/AddMeToYourContacts.css +1118 -0
  159. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts +10 -0
  160. package/lib/specialButtons/addContact/ContactCreationDialog.d.ts.map +1 -0
  161. package/lib/specialButtons/addContact/ContactCreationDialog.js +1123 -0
  162. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts +16 -0
  163. package/lib/specialButtons/addContact/addMeToYourContacts.d.ts.map +1 -0
  164. package/lib/specialButtons/addContact/addMeToYourContacts.js +136 -0
  165. package/lib/specialButtons/addContact/contactsErrors.d.ts +8 -0
  166. package/lib/specialButtons/addContact/contactsErrors.d.ts.map +1 -0
  167. package/lib/specialButtons/addContact/contactsErrors.js +106 -0
  168. package/lib/specialButtons/addContact/contactsTypes.d.ts +43 -0
  169. package/lib/specialButtons/addContact/contactsTypes.d.ts.map +1 -0
  170. package/lib/specialButtons/addContact/contactsTypes.js +5 -0
  171. package/lib/specialButtons/addContact/helpers.d.ts +7 -0
  172. package/lib/specialButtons/addContact/helpers.d.ts.map +1 -0
  173. package/lib/specialButtons/addContact/helpers.js +103 -0
  174. package/lib/specialButtons/addContact/mutations.d.ts +16 -0
  175. package/lib/specialButtons/addContact/mutations.d.ts.map +1 -0
  176. package/lib/specialButtons/addContact/mutations.js +300 -0
  177. package/lib/specialButtons/addContact/selectors.d.ts +10 -0
  178. package/lib/specialButtons/addContact/selectors.d.ts.map +1 -0
  179. package/lib/specialButtons/addContact/selectors.js +163 -0
  180. package/lib/{addMeToYourFriends.d.ts → specialButtons/addMeToYourFriends.d.ts} +6 -4
  181. package/lib/specialButtons/addMeToYourFriends.d.ts.map +1 -0
  182. package/lib/{addMeToYourFriends.js → specialButtons/addMeToYourFriends.js} +46 -11
  183. package/lib/styles/CollapsibleSection.css +519 -0
  184. package/lib/styles/EditDialogs.css +506 -686
  185. package/lib/styles/EditDialogs.responsive.css +989 -0
  186. package/lib/texts/buttonTexts.d.ts +9 -0
  187. package/lib/texts/buttonTexts.d.ts.map +1 -0
  188. package/lib/texts/buttonTexts.js +14 -0
  189. package/lib/texts/dialogTexts.d.ts +14 -0
  190. package/lib/texts/dialogTexts.d.ts.map +1 -0
  191. package/lib/texts/dialogTexts.js +19 -0
  192. package/lib/texts/messageTexts.d.ts +42 -0
  193. package/lib/texts/messageTexts.d.ts.map +1 -0
  194. package/lib/texts/messageTexts.js +47 -0
  195. package/lib/texts/profileTexts.d.ts +14 -0
  196. package/lib/texts/profileTexts.d.ts.map +1 -0
  197. package/lib/texts/profileTexts.js +19 -0
  198. package/lib/texts/qrCodeTexts.d.ts +2 -0
  199. package/lib/texts/qrCodeTexts.d.ts.map +1 -0
  200. package/lib/texts/qrCodeTexts.js +7 -0
  201. package/lib/texts.d.ts +5 -60
  202. package/lib/texts.d.ts.map +1 -1
  203. package/lib/texts.js +55 -70
  204. package/lib/ui/dialog.css +233 -0
  205. package/lib/ui/dialog.d.ts +15 -1
  206. package/lib/ui/dialog.d.ts.map +1 -1
  207. package/lib/ui/dialog.js +245 -45
  208. package/lib/ui/dialog.responsive.css +195 -0
  209. package/lib/ui/errors.d.ts.map +1 -1
  210. package/lib/ui/errors.js +2 -1
  211. package/lib/ui/spinner.d.ts +3 -0
  212. package/lib/ui/spinner.d.ts.map +1 -0
  213. package/lib/ui/spinner.js +13 -0
  214. package/lib/utils/debug.d.ts +5 -0
  215. package/lib/utils/debug.d.ts.map +1 -0
  216. package/lib/utils/debug.js +23 -0
  217. package/lib/utils/errorDisplay.d.ts +2 -0
  218. package/lib/utils/errorDisplay.d.ts.map +1 -0
  219. package/lib/utils/errorDisplay.js +19 -0
  220. package/package.json +32 -25
  221. package/lib/ChatWithMe.d.ts +0 -7
  222. package/lib/ChatWithMe.d.ts.map +0 -1
  223. package/lib/ChatWithMe.js +0 -90
  224. package/lib/QRCodeCard.d.ts.map +0 -1
  225. package/lib/addMeToYourFriends.d.ts.map +0 -1
  226. package/lib/sections/heading/camera.d.ts +0 -19
  227. package/lib/sections/heading/camera.d.ts.map +0 -1
  228. package/lib/sections/heading/camera.js +0 -199
  229. package/lib/styles/BioSection.css +0 -77
  230. package/lib/styles/CVCard.css +0 -142
  231. package/lib/styles/ChatWithMe.css +0 -6
  232. package/lib/styles/ContactInfoEditDialog.css +0 -153
  233. package/lib/styles/EducationCard.css +0 -103
  234. package/lib/styles/HeadingSection.css +0 -309
  235. package/lib/styles/ProfileCard.css +0 -66
  236. package/lib/styles/ProfileView.css +0 -65
  237. package/lib/styles/ProjectsCard.css +0 -206
  238. package/lib/styles/QRCodeCard.css +0 -43
  239. package/lib/styles/SocialCard.css +0 -89
  240. package/lib/styles/dialog.css +0 -209
  241. package/lib/styles/utilities.css +0 -740
@@ -6,25 +6,54 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.createHeadingEditDialog = createHeadingEditDialog;
7
7
  var _dialog = require("../../ui/dialog");
8
8
  var _litHtml = require("lit-html");
9
+ require("solid-ui/components/actions/button");
10
+ require("solid-ui/components/forms/select");
11
+ require("solid-ui/components/media/photo-capture");
9
12
  var _HeadingSection = require("./HeadingSection");
10
13
  require("../../styles/EditDialogs.css");
11
- var _rdflib = require("rdflib");
12
14
  var _mutations = require("./mutations");
13
15
  var _phoneCountries = require("../shared/phoneCountries");
14
16
  var _contactTypeUtils = require("../shared/contactTypeUtils");
15
17
  var _rowState = require("../shared/rowState");
16
18
  var _textUtils = require("../../textUtils");
17
19
  var _texts = require("../../texts");
20
+ var _debug = require("../../utils/debug");
18
21
  var _profileIcons = require("../../icons-svg/profileIcons");
19
22
  var _sanitizeUtils = require("../shared/sanitizeUtils");
20
23
  var _dateHelpers = require("./dateHelpers");
21
24
  var _imageHelpers = require("./imageHelpers");
22
- var _camera = require("./camera");
23
25
  /* Note: new design - has address type in More Edit Contacts for now we will leave
24
26
  out Address Type, but a ticket will be created to add type later
25
27
  so I will keep the code and just comment it out for now.
26
28
  new design - has country code, will comment out code for now and create a ticket to add later. */
27
29
 
30
+ const HEADING_PHONE_TYPE_OPTIONS = [{
31
+ label: 'Mobile',
32
+ value: 'Mobile'
33
+ }, {
34
+ label: 'Home',
35
+ value: 'Home'
36
+ }, {
37
+ label: 'Work',
38
+ value: 'Work'
39
+ }];
40
+ const HEADING_EMAIL_TYPE_OPTIONS = [{
41
+ label: 'Personal',
42
+ value: 'Personal'
43
+ }, {
44
+ label: 'Office',
45
+ value: 'Office'
46
+ }];
47
+ const HEADING_PRONOUN_OPTIONS = [{
48
+ label: 'He/Him',
49
+ value: 'He/Him'
50
+ }, {
51
+ label: 'She/Her',
52
+ value: 'She/Her'
53
+ }, {
54
+ label: 'They/Them',
55
+ value: 'They/Them'
56
+ }];
28
57
  function isContactPointRow(row) {
29
58
  return 'value' in row;
30
59
  }
@@ -34,6 +63,47 @@ function isAddressRow(row) {
34
63
  function isProfileBasicRow(row) {
35
64
  return 'name' in row;
36
65
  }
66
+ function normalizeHeadingContactTypeValue(value, options) {
67
+ return options.some(option => option.value === value) ? value : options[0]?.value || '';
68
+ }
69
+ function readHeadingContactTypeChange(event) {
70
+ const customEvent = event;
71
+ if (typeof customEvent.detail?.value === 'string') {
72
+ return customEvent.detail.value;
73
+ }
74
+ const target = event.target;
75
+ return typeof target?.value === 'string' ? target.value : '';
76
+ }
77
+ function getHeadingContactTypeOptions(kind) {
78
+ return kind === 'phone' ? HEADING_PHONE_TYPE_OPTIONS : HEADING_EMAIL_TYPE_OPTIONS;
79
+ }
80
+ function getHeadingContactTypeValue(kind, formState) {
81
+ const row = kind === 'phone' ? formState.phone : formState.email;
82
+ return normalizeHeadingContactTypeValue(row?.type || '', getHeadingContactTypeOptions(kind));
83
+ }
84
+ function withDefaultHeadingContactType(row, kind) {
85
+ return {
86
+ ...row,
87
+ type: normalizeHeadingContactTypeValue(row.type || '', getHeadingContactTypeOptions(kind))
88
+ };
89
+ }
90
+ function initializeHeadingContactTypeSelects(form, formState) {
91
+ const selectElements = form.querySelectorAll('solid-ui-select[data-heading-contact-type-kind]');
92
+ selectElements.forEach(selectElement => {
93
+ const kind = selectElement.dataset.headingContactTypeKind;
94
+ if (!kind) return;
95
+ selectElement.options = getHeadingContactTypeOptions(kind);
96
+ selectElement.value = getHeadingContactTypeValue(kind, formState);
97
+ selectElement.label = '';
98
+ });
99
+ }
100
+ function initializeHeadingPronounsSelect(form, formState) {
101
+ const selectElement = form.querySelector('solid-ui-select[data-heading-basic-field="pronouns"]');
102
+ if (!selectElement) return;
103
+ selectElement.options = HEADING_PRONOUN_OPTIONS;
104
+ selectElement.value = normalizePronounsValue(formState.basicInfo?.pronouns || '');
105
+ selectElement.label = '';
106
+ }
37
107
  function rowHasContent(row) {
38
108
  if (isContactPointRow(row)) {
39
109
  return (0, _textUtils.hasNonEmptyText)(row.value);
@@ -42,7 +112,7 @@ function rowHasContent(row) {
42
112
  return [row.streetAddress, row.locality, row.region, row.postalCode, row.countryName].some(_textUtils.hasNonEmptyText);
43
113
  }
44
114
  if (isProfileBasicRow(row)) {
45
- return [row.name, row.nickname, row.imageSrc, row.location, row.pronouns, row.dateOfBirth, row.jobTitle, row.orgName].some(_textUtils.hasNonEmptyText);
115
+ return [row.name, row.nickname, row.imageSrc, row.location, row.pronouns, row.dateOfBirth].some(_textUtils.hasNonEmptyText);
46
116
  }
47
117
  return false;
48
118
  }
@@ -62,14 +132,14 @@ function toFormState(profileData) {
62
132
  location: (0, _textUtils.sanitizeTextValue)((0, _textUtils.toText)(profileData.location || '')),
63
133
  pronouns: normalizePronounsValue((0, _textUtils.toText)(profileData.pronouns || '')),
64
134
  dateOfBirth: (0, _textUtils.sanitizeTextValue)((0, _textUtils.toText)(profileData.dateOfBirth || '')),
65
- jobTitle: (0, _textUtils.sanitizeTextValue)((0, _textUtils.toText)(profileData.jobTitle || '')),
66
- orgName: (0, _textUtils.sanitizeTextValue)((0, _textUtils.toText)(profileData.orgName || '')),
67
135
  entryNode: (0, _textUtils.toText)(profileData.entryNode),
68
136
  status: (0, _textUtils.toText)(profileData.entryNode) ? 'existing' : 'new'
69
137
  };
70
138
  const primaryEmail = profileData.primaryEmail;
71
139
  const primaryPhone = profileData.primaryPhone;
72
140
  const primaryAddress = profileData.primaryAddress;
141
+ const emailTypeWasMissing = !(0, _contactTypeUtils.normalizeEmailTypeForEdit)(primaryEmail?.type);
142
+ const phoneTypeWasMissing = !(0, _contactTypeUtils.normalizePhoneTypeForEdit)(primaryPhone?.type);
73
143
  const normalizedEmailType = (0, _contactTypeUtils.normalizeEmailTypeForEdit)(primaryEmail?.type);
74
144
  const normalizedPhoneType = (0, _contactTypeUtils.normalizePhoneTypeForEdit)(primaryPhone?.type);
75
145
  const email = {
@@ -102,8 +172,6 @@ function toFormState(profileData) {
102
172
  location: '',
103
173
  pronouns: '',
104
174
  dateOfBirth: '',
105
- jobTitle: '',
106
- orgName: '',
107
175
  entryNode: '',
108
176
  status: 'new'
109
177
  },
@@ -128,13 +196,51 @@ function toFormState(profileData) {
128
196
  type: '',
129
197
  entryNode: '',
130
198
  status: 'new'
131
- }
199
+ },
200
+ emailTypeWasMissing,
201
+ phoneTypeWasMissing,
202
+ imagePreviewSrc: '',
203
+ clearImagePreview: () => undefined
204
+ };
205
+ }
206
+ function setHeadingImagePreview(formState, file) {
207
+ formState.clearImagePreview();
208
+ if (typeof URL.createObjectURL !== 'function') {
209
+ formState.imagePreviewSrc = '';
210
+ formState.clearImagePreview = () => undefined;
211
+ return;
212
+ }
213
+ const previewUrl = URL.createObjectURL(file);
214
+ formState.imagePreviewSrc = previewUrl;
215
+ formState.clearImagePreview = () => {
216
+ URL.revokeObjectURL(previewUrl);
217
+ formState.imagePreviewSrc = '';
218
+ formState.clearImagePreview = () => undefined;
219
+ };
220
+ }
221
+ function setResolvedHeadingPreview(formState, resolvedImageSrc) {
222
+ formState.clearImagePreview();
223
+ if (!resolvedImageSrc) {
224
+ return;
225
+ }
226
+ formState.imagePreviewSrc = resolvedImageSrc;
227
+ if (resolvedImageSrc.startsWith('blob:') && typeof URL.revokeObjectURL === 'function') {
228
+ formState.clearImagePreview = () => {
229
+ URL.revokeObjectURL(resolvedImageSrc);
230
+ formState.imagePreviewSrc = '';
231
+ formState.clearImagePreview = () => undefined;
232
+ };
233
+ return;
234
+ }
235
+ formState.clearImagePreview = () => {
236
+ formState.imagePreviewSrc = '';
237
+ formState.clearImagePreview = () => undefined;
132
238
  };
133
239
  }
134
240
  function mapEmailOpsForSave(ops) {
135
241
  const mapRow = row => ({
136
- ...row,
137
- type: (0, _contactTypeUtils.toSavedHeadingEmailType)(row.type)
242
+ ...withDefaultHeadingContactType(row, 'email'),
243
+ type: (0, _contactTypeUtils.toSavedHeadingEmailType)(withDefaultHeadingContactType(row, 'email').type)
138
244
  });
139
245
  return {
140
246
  create: ops.create.map(mapRow),
@@ -144,8 +250,8 @@ function mapEmailOpsForSave(ops) {
144
250
  }
145
251
  function mapPhoneOpsForSave(ops) {
146
252
  const mapRow = row => ({
147
- ...row,
148
- type: (0, _contactTypeUtils.toSavedHeadingPhoneType)(row.type)
253
+ ...withDefaultHeadingContactType(row, 'phone'),
254
+ type: (0, _contactTypeUtils.toSavedHeadingPhoneType)(withDefaultHeadingContactType(row, 'phone').type)
149
255
  });
150
256
  return {
151
257
  create: ops.create.map(mapRow),
@@ -153,35 +259,26 @@ function mapPhoneOpsForSave(ops) {
153
259
  remove: ops.remove.map(mapRow)
154
260
  };
155
261
  }
156
-
157
- /* Will use later function renderCountryPrefixSelect(
158
- name: string,
159
- value: string,
160
- label: string,
161
- onChange: (event: Event) => void
162
- ) {
163
- return html`
164
- <label class="label profile-edit-dialog__phone-prefix-field" aria-label=${label}>
165
- <select class="phonePrefixSelect" name=${name} .value=${value} @change=${onChange}>
166
- ${COUNTRY_PREFIX_OPTIONS.map((option) => html`
167
- <option value=${option.dialCode}>
168
- ${countryCodeToFlag(option.iso2)} ${option.dialCode}
169
- </option>
170
- `)}
171
- </select>
172
- </label>
173
- `
174
- } */
175
-
262
+ function summarizeHeadingContactOps(row, kind, typeWasMissing) {
263
+ const ops = (0, _rowState.summarizeRowOps)([row], rowHasContent);
264
+ if (typeWasMissing && row.entryNode && row.status === 'existing' && rowHasContent(row) && ops.create.length === 0 && ops.update.length === 0 && ops.remove.length === 0) {
265
+ return {
266
+ create: ops.create,
267
+ update: [withDefaultHeadingContactType({
268
+ ...row,
269
+ status: 'modified'
270
+ }, kind)],
271
+ remove: ops.remove
272
+ };
273
+ }
274
+ return ops;
275
+ }
176
276
  function renderContactPhoneInput({
177
277
  phone
178
278
  }) {
179
- const label = 'Phone Number';
180
- /* const countryCodeLabel = 'Country Calling Code' */
181
- /* const prefixInputName = 'phone-prefix' */
182
- const typeLabel = 'Phone Type';
279
+ const label = 'Phone Number 1';
280
+ const typeLabel = 'Phone Type 1';
183
281
  const inputName = 'phone-value';
184
- const typeInputName = 'phone-type';
185
282
  const splitValue = (0, _phoneCountries.splitPhoneValue)(phone?.value || '');
186
283
  let selectedDialCode = splitValue.dialCode;
187
284
  const handleValueInput = e => {
@@ -191,19 +288,8 @@ function renderContactPhoneInput({
191
288
  (0, _rowState.applyRowFieldChange)(phone, 'value', (0, _phoneCountries.combinePhoneValue)(selectedDialCode, nextValue), rowHasContent);
192
289
  }
193
290
  };
194
- /* Leaving here for when we add country code back in
195
- const handleCountryCodeInput = (e: Event) => {
196
- const target = e.target as HTMLSelectElement
197
- selectedDialCode = target.value
198
- if (phone) {
199
- const localNumber = splitPhoneValue(phone.value).localNumber
200
- applyRowFieldChange(phone, 'value', combinePhoneValue(selectedDialCode, localNumber), rowHasContent)
201
- }
202
- } */
203
-
204
291
  const handleTypeInput = e => {
205
- const target = e.target;
206
- const nextType = target.value;
292
+ const nextType = readHeadingContactTypeChange(e);
207
293
  if (phone) {
208
294
  (0, _rowState.applyRowSelectChange)(phone, 'type', nextType);
209
295
  }
@@ -221,7 +307,7 @@ function renderContactPhoneInput({
221
307
  data-contact-field="value"
222
308
  data-entry-node=${phone?.entryNode || ''}
223
309
  data-row-status=${phone?.status || 'n/a'}
224
- placeholder="Phone Number"
310
+ placeholder=${label}
225
311
  autocomplete="tel-national"
226
312
  inputmode="tel"
227
313
  @input=${handleValueInput}
@@ -229,11 +315,16 @@ function renderContactPhoneInput({
229
315
  </label>
230
316
  </div>
231
317
  <label aria-label=${typeLabel} class="label profile-edit-dialog__field-type profile-edit-dialog__field-type--contact-point">
232
- <select class="input" name=${typeInputName} id="phone-type-select-${inputName}" @change=${handleTypeInput} .value=${phone?.type || ''}>
233
- <option value="Mobile">Mobile</option>
234
- <option value="Home">Home</option>
235
- <option value="Work">Work</option>
236
- </select>
318
+ <solid-ui-select
319
+ class="profile-edit-dialog__type-select"
320
+ id=${`phone-type-select-${inputName}`}
321
+ data-heading-contact-type-kind="phone"
322
+ aria-label=${typeLabel}
323
+ .label=${''}
324
+ .options=${HEADING_PHONE_TYPE_OPTIONS}
325
+ .value=${normalizeHeadingContactTypeValue(phone?.type || '', HEADING_PHONE_TYPE_OPTIONS)}
326
+ @change=${handleTypeInput}
327
+ ></solid-ui-select>
237
328
  </label>
238
329
  </div>
239
330
  `;
@@ -244,7 +335,6 @@ function renderContactEmailInputRow({
244
335
  const label = 'Email Address';
245
336
  const typeLabel = 'Email Type';
246
337
  const inputName = 'email-value';
247
- const typeInputName = 'email-type';
248
338
  const handleValueInput = e => {
249
339
  const target = e.target;
250
340
  const nextValue = (0, _sanitizeUtils.sanitizeEmailValue)(target.value);
@@ -253,8 +343,7 @@ function renderContactEmailInputRow({
253
343
  }
254
344
  };
255
345
  const handleTypeInput = e => {
256
- const target = e.target;
257
- const nextType = target.value;
346
+ const nextType = readHeadingContactTypeChange(e);
258
347
  if (email) {
259
348
  (0, _rowState.applyRowSelectChange)(email, 'type', nextType);
260
349
  }
@@ -278,10 +367,16 @@ function renderContactEmailInputRow({
278
367
  />
279
368
  </label>
280
369
  <label aria-label=${typeLabel} class="label profile-edit-dialog__field-type profile-edit-dialog__field-type--contact-point">
281
- <select class="input" name=${typeInputName} id="email-type-select-${inputName}" @change=${handleTypeInput} .value=${email?.type || ''}>
282
- <option value="Personal">Personal</option>
283
- <option value="Office">Office</option>
284
- </select>
370
+ <solid-ui-select
371
+ class="profile-edit-dialog__type-select"
372
+ id=${`email-type-select-${inputName}`}
373
+ data-heading-contact-type-kind="email"
374
+ aria-label=${typeLabel}
375
+ .label=${''}
376
+ .options=${HEADING_EMAIL_TYPE_OPTIONS}
377
+ .value=${normalizeHeadingContactTypeValue(email?.type || '', HEADING_EMAIL_TYPE_OPTIONS)}
378
+ @change=${handleTypeInput}
379
+ ></solid-ui-select>
285
380
  </label>
286
381
  </div>
287
382
  `;
@@ -403,15 +498,19 @@ function renderContactAddressInput({
403
498
  </div>
404
499
  `;
405
500
  }
406
- function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerender) {
501
+ function renderHeadingInfoInput(store, subject, formState, rerender) {
502
+ const {
503
+ basicInfo,
504
+ phone,
505
+ email,
506
+ imagePreviewSrc
507
+ } = formState;
407
508
  const imageSrcLabel = 'Profile Photo';
408
509
  const recommendedImageToLoad = 'Recommended: Square JPG, PNG. Max 2MB.';
409
510
  const nameLabel = 'Full Name';
410
511
  const nicknameLabel = 'Nickname';
411
512
  const pronounsLabel = 'Pronouns';
412
513
  const dateOfBirthLabel = 'DOB';
413
- const jobTitleLabel = 'Job Title';
414
- const orgNameLabel = 'Organization Name';
415
514
  const handleBasicInfoInput = field => e => {
416
515
  const target = e.target;
417
516
  const nextValue = (0, _sanitizeUtils.sanitizeBasicInputFieldValue)(target.value);
@@ -427,10 +526,9 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
427
526
  }
428
527
  };
429
528
  const handlePronounsInput = e => {
430
- const target = e.target;
431
- const nextType = target.value;
529
+ const nextValue = normalizePronounsValue(readHeadingContactTypeChange(e));
432
530
  if (basicInfo) {
433
- (0, _rowState.applyRowSelectChange)(basicInfo, 'pronouns', nextType);
531
+ (0, _rowState.applyRowSelectChange)(basicInfo, 'pronouns', nextValue);
434
532
  }
435
533
  };
436
534
  const handleUpload = async e => {
@@ -439,27 +537,31 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
439
537
  const fileInput = dom.createElement('input');
440
538
  fileInput.type = 'file';
441
539
  fileInput.accept = 'image/*';
540
+ fileInput.hidden = true;
541
+ const cleanupFileInput = () => {
542
+ fileInput.remove();
543
+ };
442
544
  fileInput.addEventListener('change', async () => {
443
545
  const file = fileInput.files?.[0];
546
+ cleanupFileInput();
444
547
  if (!file || !basicInfo) return;
445
548
  try {
446
549
  const uploadedUri = await (0, _imageHelpers.uploadPhotoFile)(store, subject, file);
550
+ setHeadingImagePreview(formState, file);
447
551
  (0, _rowState.applyRowFieldChange)(basicInfo, 'imageSrc', uploadedUri, rowHasContent);
448
552
  rerender();
449
553
  } catch (error) {
450
- console.error('Profile image upload failed', error);
554
+ (0, _debug.error)('Profile image upload failed', error);
451
555
  }
556
+ }, {
557
+ once: true
452
558
  });
559
+ dom.body.appendChild(fileInput);
453
560
  fileInput.click();
454
561
  };
455
-
456
- /* The handleCameraClick function was generated by AI Model: GPT-5.3-Codex */
457
- /* Prompt: Write a function handleCameraClick that uses the cameraCaptureControl to
458
- capture an image and update the profile photo in the heading section. */
459
562
  const handleCameraClick = async e => {
460
563
  e.preventDefault();
461
564
  const button = e.currentTarget;
462
- const dom = button?.ownerDocument || document;
463
565
  const headingPhotoRow = button?.closest('.profile-edit-dialog__row--heading-photo');
464
566
  const hostRow = headingPhotoRow?.nextElementSibling;
465
567
  const frame = hostRow?.querySelector('.profile-edit-dialog__image-camera-capture-frame');
@@ -467,51 +569,72 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
467
569
  frame.hidden = false;
468
570
  frame.dataset.active = 'true';
469
571
  frame.replaceChildren();
470
- const getImageDoc = () => {
471
- const docUri = subject.doc().uri;
472
- const lastSlash = docUri.lastIndexOf('/');
473
- const directoryUri = lastSlash >= 0 ? docUri.slice(0, lastSlash + 1) : docUri;
474
- const randomSuffix = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : `${Date.now()}_${Math.floor(Math.random() * 1e9)}`;
475
- return (0, _rdflib.sym)(`${directoryUri}camera_${randomSuffix}.png`);
476
- };
477
- const onCameraDone = async imageDoc => {
572
+ const closeCameraFrame = () => {
478
573
  frame.replaceChildren();
479
574
  frame.hidden = true;
480
575
  frame.dataset.active = 'false';
481
- if (imageDoc?.uri && basicInfo) {
482
- (0, _rowState.applyRowFieldChange)(basicInfo, 'imageSrc', imageDoc.uri, rowHasContent);
483
- rerender();
484
- }
485
576
  };
486
577
  try {
487
- const control = (0, _camera.cameraCaptureControl)(dom, store, getImageDoc, onCameraDone);
488
- frame.appendChild(control);
578
+ const photoCapture = document.createElement('solid-ui-photo-capture');
579
+ photoCapture.classList.add('profile-edit-dialog__photo-capture');
580
+ photoCapture.heading = '';
581
+ photoCapture.captureLabel = 'Take Photo';
582
+ photoCapture.confirmLabel = 'Use Photo';
583
+ photoCapture.retakeLabel = 'Retake';
584
+ photoCapture.cancelLabel = 'Close camera';
585
+ photoCapture.presentation = 'inline';
586
+ photoCapture.showTrigger = false;
587
+ photoCapture.showCancelButton = true;
588
+ photoCapture.autoCloseOnCapture = false;
589
+ photoCapture.fileNamePrefix = 'camera';
590
+ photoCapture.facingMode = 'user';
591
+ photoCapture.open = true;
592
+ photoCapture.addEventListener('cancel', event => {
593
+ event.preventDefault();
594
+ event.stopPropagation();
595
+ closeCameraFrame();
596
+ });
597
+ photoCapture.addEventListener('photo-captured', async event => {
598
+ const detail = event.detail;
599
+ if (!detail?.file || !basicInfo) return;
600
+ try {
601
+ const uploadedUri = await (0, _imageHelpers.uploadPhotoFile)(store, subject, detail.file);
602
+ closeCameraFrame();
603
+ setHeadingImagePreview(formState, detail.file);
604
+ (0, _rowState.applyRowFieldChange)(basicInfo, 'imageSrc', uploadedUri, rowHasContent);
605
+ rerender();
606
+ } catch (error) {
607
+ (0, _debug.error)('Profile camera upload failed', error);
608
+ }
609
+ });
610
+ frame.appendChild(photoCapture);
489
611
  } catch (error) {
490
- frame.hidden = true;
491
- frame.dataset.active = 'false';
492
- frame.replaceChildren();
493
- console.error('Camera control failed to initialize', error);
612
+ closeCameraFrame();
613
+ (0, _debug.error)('Camera control failed to initialize', error);
494
614
  }
495
615
  };
496
616
  const handleDelete = async _e => {
497
617
  if (!basicInfo) return;
618
+ formState.clearImagePreview();
498
619
  (0, _rowState.applyRowFieldChange)(basicInfo, 'imageSrc', '', rowHasContent);
499
620
  rerender();
500
621
  };
501
622
  return (0, _litHtml.html)`
502
623
  <div class="profile-edit-dialog__row profile-edit-dialog__row--heading-photo">
503
- <header class="mb-md" aria-label="Profile Image">
624
+ <header class="profile-edit-dialog__image-preview-header" aria-label="Profile Image">
504
625
  <div class="profile-edit-dialog__image-frame">
505
- ${(0, _HeadingSection.Image)(basicInfo.imageSrc, basicInfo.name)}
506
- <button
626
+ ${(0, _HeadingSection.Image)(imagePreviewSrc || basicInfo.imageSrc, basicInfo.name)}
627
+ <solid-ui-button
507
628
  type="button"
508
- class="profile-edit-dialog__image-camera-button flex-center"
629
+ class="profile-edit-dialog__image-camera-button"
630
+ variant="icon"
631
+ size="md"
509
632
  aria-label="Take a photo"
510
633
  title="Take a photo"
511
634
  @click=${handleCameraClick}
512
635
  >
513
- ${_profileIcons.cameraIcon}
514
- </button>
636
+ <span slot="icon" aria-hidden="true">${_profileIcons.cameraIcon}</span>
637
+ </solid-ui-button>
515
638
  </div>
516
639
  </header>
517
640
 
@@ -520,31 +643,37 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
520
643
  <p class="profile-edit-dialog__image-preview-description">${recommendedImageToLoad}</p>
521
644
 
522
645
  <div class="profile-edit-dialog__image-preview-actions">
523
- <button
646
+ <solid-ui-button
524
647
  type="button"
525
- class="profile-edit-dialog__image-button profile-edit-dialog__image-upload-button flex-center"
648
+ variant="secondary"
649
+ size="md"
650
+ label="Upload New"
651
+ class="profile-edit-dialog__image-button profile-edit-dialog__image-upload-button"
526
652
  aria-label="Upload new profile photo"
527
653
  title="Upload New"
528
654
  @click=${handleUpload}
529
655
  >
530
656
  Upload New
531
- </button>
532
- <button
657
+ </solid-ui-button>
658
+ <solid-ui-button
533
659
  type="button"
534
- class="profile-edit-dialog__image-button profile-edit-dialog__image-remove-button flex-center"
660
+ variant="secondary"
661
+ size="md"
662
+ label="Remove"
663
+ class="profile-edit-dialog__image-button profile-edit-dialog__image-remove-button"
535
664
  aria-label="Delete profile photo"
536
665
  title="Remove"
537
666
  @click=${handleDelete}
538
667
  >
539
668
  Remove
540
- </button>
669
+ </solid-ui-button>
541
670
  </div>
542
671
  </div>
543
672
  </div>
544
673
  <div class="profile-edit-dialog__image-camera-capture-row">
545
674
  <div class="profile-edit-dialog__image-camera-capture-frame" hidden></div>
546
675
  </div>
547
- <div class="profile-edit flex-column gap-lg">
676
+ <div class="profile-edit">
548
677
  <div class="profile-edit-dialog__row profile-edit-dialog__row--equal">
549
678
  <label aria-label=${nameLabel} class="label profile-edit-dialog__field">
550
679
  ${nameLabel}
@@ -580,19 +709,25 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
580
709
  />
581
710
  </label>
582
711
  </div>
583
- <div class="profile-edit-dialog__row profile-edit-dialog__row--equal">
712
+ <div class="profile-edit-dialog__row profile-edit-dialog__row--equal profile-edit-dialog__row--heading-dob">
584
713
  <label aria-label=${pronounsLabel} class="label profile-edit-dialog__field-type profile-edit-dialog__field--stack">
585
714
  ${pronounsLabel}
586
- <select class="input" name="pronouns" @change=${handlePronounsInput} .value=${basicInfo?.pronouns || ''}>
587
- <option value="He/Him">He/Him</option>
588
- <option value="She/Her">She/Her</option>
589
- <option value="They/Them">They/Them</option>
590
- </select>
715
+ <solid-ui-select
716
+ class="profile-edit-dialog__type-select"
717
+ id="heading-pronouns-select"
718
+ name="pronouns"
719
+ data-heading-basic-field="pronouns"
720
+ aria-label=${pronounsLabel}
721
+ .label=${''}
722
+ .options=${HEADING_PRONOUN_OPTIONS}
723
+ .value=${normalizePronounsValue(basicInfo?.pronouns || '')}
724
+ @change=${handlePronounsInput}
725
+ ></solid-ui-select>
591
726
  </label>
592
- <label aria-label=${dateOfBirthLabel} class="label profile-edit-dialog__field">
727
+ <label aria-label=${dateOfBirthLabel} class="label profile-edit-dialog__field profile-edit-dialog__field--dob">
593
728
  ${dateOfBirthLabel}
594
729
  <input
595
- class="input"
730
+ class="input profile-edit-dialog__input--dob"
596
731
  type="date"
597
732
  name="profile-date-of-birth"
598
733
  .value=${(0, _dateHelpers.toStorageDateISO)(basicInfo?.dateOfBirth)}
@@ -607,40 +742,6 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
607
742
  />
608
743
  </label>
609
744
  </div>
610
- <div class="profile-edit-dialog__row profile-edit-dialog__row--equal">
611
- <label aria-label=${jobTitleLabel} class="label profile-edit-dialog__field">
612
- ${jobTitleLabel}
613
- <input
614
- class="input"
615
- type="text"
616
- name="jobTitle"
617
- .value=${basicInfo?.jobTitle || ''}
618
- data-contact-field="jobTitle"
619
- data-entry-node=${basicInfo?.entryNode || ''}
620
- data-row-status=${basicInfo?.status || 'n/a'}
621
- placeholder="Job Title"
622
- autocomplete="organization-title"
623
- inputmode="text"
624
- @change=${handleBasicInfoInput('jobTitle')}
625
- />
626
- </label>
627
- <label aria-label=${orgNameLabel} class="label profile-edit-dialog__field">
628
- ${orgNameLabel}
629
- <input
630
- class="input"
631
- type="text"
632
- name="orgName"
633
- .value=${basicInfo?.orgName || ''}
634
- data-contact-field="orgName"
635
- data-entry-node=${basicInfo?.entryNode || ''}
636
- data-row-status=${basicInfo?.status || 'n/a'}
637
- placeholder="Organization Name"
638
- autocomplete="organization-name"
639
- inputmode="text"
640
- @change=${handleBasicInfoInput('orgName')}
641
- />
642
- </label>
643
- </div>
644
745
  <div class="profile-edit-dialog__row profile-edit-dialog__row--equal">
645
746
  <div class="profile-edit-dialog__field profile-edit-dialog__field--full">
646
747
  ${renderContactPhoneInput({
@@ -659,16 +760,18 @@ function renderHeadingInfoInput(store, subject, basicInfo, phone, email, rerende
659
760
  function renderHeadingEditTemplate(form, formState, store, subject, viewerMode) {
660
761
  const rerender = () => renderHeadingEditTemplate(form, formState, store, subject, viewerMode);
661
762
  (0, _litHtml.render)((0, _litHtml.html)`
662
- ${renderHeadingInfoInput(store, subject, formState.basicInfo, formState.phone, formState.email, rerender)}
763
+ ${renderHeadingInfoInput(store, subject, formState, rerender)}
663
764
  ${renderContactAddressInput({
664
765
  address: formState.address
665
766
  })}
666
767
  ${viewerMode !== 'owner' ? (0, _litHtml.html)`<p class="profile-edit-dialog__login-message">${_texts.ownerLoginRequiredDialogMessageText}</p>` : null}
667
768
  `, form);
769
+ initializeHeadingContactTypeSelects(form, formState);
770
+ initializeHeadingPronounsSelect(form, formState);
668
771
  }
669
772
  function createHeadingEditForm(store, subject, profileData, viewerMode) {
670
773
  const form = document.createElement('form');
671
- form.classList.add('profile__edit-form', 'profile-edit-dialog--heading', 'flex-column', 'gap-sm');
774
+ form.classList.add('profile__edit-form', 'profile__edit-form--heading', 'profile-edit-dialog--heading');
672
775
  form.autocomplete = 'off';
673
776
  form.setAttribute('data-lpignore', 'true');
674
777
  form.setAttribute('data-1p-ignore', 'true');
@@ -680,31 +783,54 @@ function createHeadingEditForm(store, subject, profileData, viewerMode) {
680
783
  formState
681
784
  };
682
785
  }
786
+ function isValidHeadingEmailAddress(value) {
787
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
788
+ }
789
+ function isValidHeadingPhoneNumber(value) {
790
+ return /^\d+$/.test(value);
791
+ }
683
792
  function validateHeadingDataBeforeSave(formState) {
684
- const basicInfoOps = (0, _rowState.summarizeRowOps)([formState.basicInfo], rowHasContent);
685
- const phoneOps = (0, _rowState.summarizeRowOps)([formState.phone], rowHasContent);
686
- const emailOps = (0, _rowState.summarizeRowOps)([formState.email], rowHasContent);
687
- const addressOps = (0, _rowState.summarizeRowOps)([formState.address], rowHasContent);
688
- const hasChanges = basicInfoOps.create.length > 0 || basicInfoOps.update.length > 0 || basicInfoOps.remove.length > 0 || phoneOps.create.length > 0 || phoneOps.update.length > 0 || phoneOps.remove.length > 0 || emailOps.create.length > 0 || emailOps.update.length > 0 || emailOps.remove.length > 0 || addressOps.create.length > 0 || addressOps.update.length > 0 || addressOps.remove.length > 0;
689
- if (!hasChanges) return 'No intro changes detected.';
793
+ const {
794
+ localNumber
795
+ } = (0, _phoneCountries.splitPhoneValue)(formState.phone?.value || '');
796
+ if (rowHasContent(formState.phone) && !isValidHeadingPhoneNumber(localNumber)) {
797
+ return 'Phone Number 1 should contain only numbers.';
798
+ }
799
+ if (rowHasContent(formState.email) && !isValidHeadingEmailAddress(formState.email?.value || '')) {
800
+ return 'Email address must be a valid email address.';
801
+ }
690
802
  return null;
691
803
  }
692
- async function createHeadingEditDialog(event, store, subject, profileData, viewerMode, onSaved) {
804
+ async function createHeadingEditDialog(_event, store, subject, profileData, viewerMode, onSaved) {
693
805
  const dom = document;
694
806
  const originalPhotoUri = (0, _textUtils.sanitizeTextValue)((0, _textUtils.toText)(profileData.imageSrc || ''));
695
807
  const {
696
808
  form,
697
809
  formState
698
810
  } = createHeadingEditForm(store, subject, profileData, viewerMode);
811
+ if (formState.basicInfo.imageSrc) {
812
+ const resolvedImageSrc = await (0, _imageHelpers.resolvePhotoDisplaySrc)(store, formState.basicInfo.imageSrc);
813
+ if (resolvedImageSrc && resolvedImageSrc !== formState.basicInfo.imageSrc) {
814
+ setResolvedHeadingPreview(formState, resolvedImageSrc);
815
+ renderHeadingEditTemplate(form, formState, store, subject, viewerMode);
816
+ }
817
+ }
699
818
  const result = await (0, _dialog.openInputDialog)({
700
819
  title: _texts.editHeadingDialogTitleText,
701
820
  dom,
702
821
  form,
703
822
  headerAction: {
704
- type: 'close'
823
+ type: 'none'
705
824
  },
706
825
  submitLabel: _texts.dialogSubmitLabelText,
707
826
  cancelLabel: _texts.dialogCancelLabelText,
827
+ shouldCloseWithoutSave: () => {
828
+ const basicInfoOps = (0, _rowState.summarizeRowOps)([formState.basicInfo], rowHasContent);
829
+ const phoneOps = summarizeHeadingContactOps(formState.phone, 'phone', formState.phoneTypeWasMissing);
830
+ const emailOps = summarizeHeadingContactOps(formState.email, 'email', formState.emailTypeWasMissing);
831
+ const addressOps = (0, _rowState.summarizeRowOps)([formState.address], rowHasContent);
832
+ return basicInfoOps.create.length === 0 && basicInfoOps.update.length === 0 && basicInfoOps.remove.length === 0 && phoneOps.create.length === 0 && phoneOps.update.length === 0 && phoneOps.remove.length === 0 && emailOps.create.length === 0 && emailOps.update.length === 0 && emailOps.remove.length === 0 && addressOps.create.length === 0 && addressOps.update.length === 0 && addressOps.remove.length === 0;
833
+ },
708
834
  validate: () => {
709
835
  if (viewerMode !== 'owner') {
710
836
  return _texts.ownerLoginRequiredDialogMessageText;
@@ -712,8 +838,8 @@ async function createHeadingEditDialog(event, store, subject, profileData, viewe
712
838
  return validateHeadingDataBeforeSave(formState);
713
839
  },
714
840
  onSave: async () => {
715
- const phoneOps = (0, _rowState.summarizeRowOps)([formState.phone], rowHasContent);
716
- const emailOps = (0, _rowState.summarizeRowOps)([formState.email], rowHasContent);
841
+ const phoneOps = summarizeHeadingContactOps(formState.phone, 'phone', formState.phoneTypeWasMissing);
842
+ const emailOps = summarizeHeadingContactOps(formState.email, 'email', formState.emailTypeWasMissing);
717
843
  const plan = {
718
844
  basicOps: (0, _rowState.summarizeRowOps)([formState.basicInfo], rowHasContent),
719
845
  phoneOps: mapPhoneOpsForSave(phoneOps),
@@ -726,13 +852,12 @@ async function createHeadingEditDialog(event, store, subject, profileData, viewe
726
852
  try {
727
853
  await (0, _imageHelpers.deletePhotoFile)(store, subject, originalPhotoUri);
728
854
  } catch (error) {
729
- console.warn('Profile image file delete failed', error);
855
+ (0, _debug.warn)('Profile image file delete failed', error);
730
856
  }
731
857
  }
732
858
  },
733
859
  formatSaveError: error => {
734
- const message = error instanceof Error ? error.message : String(error);
735
- return `${_texts.saveHeadingUpdatesFailedPrefixText} ${message}`;
860
+ return error instanceof Error ? error.message : _texts.saveHeadingUpdatesFailedMessageText;
736
861
  }
737
862
  });
738
863
  if (!result) return;