@@ -6,7 +6,6 @@ import IconBlackDuration from 'assets/images/icon-black-calendar.svg';
66import IconBlackLocation from 'assets/images/icon-black-location.svg' ;
77import IconBlackPayment from 'assets/images/icon-black-payment.svg' ;
88import iconBlackSkills from 'assets/images/icon-skills.png' ;
9- import IconTimezone from 'assets/images/icon-timezone.svg' ;
109
1110import './style.scss' ;
1211
@@ -22,12 +21,6 @@ const WORKLOAD_LABELS = {
2221 FRACTIONAL : 'Fractional' ,
2322} ;
2423
25- const ANTICIPATED_START_LABELS = {
26- IMMEDIATE : 'Immediate' ,
27- FEW_DAYS : 'Few Days' ,
28- FEW_WEEKS : 'Few Weeks' ,
29- } ;
30-
3124const STATUS_LABELS = {
3225 OPEN : 'Open' ,
3326 PENDING_ASSIGNMENT : 'Pending Assignment' ,
@@ -36,62 +29,20 @@ const STATUS_LABELS = {
3629 CLOSED : 'Closed' ,
3730} ;
3831
39- const UUID_PATTERN = / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } $ / i;
40- const UNKNOWN_SKILL_LABEL = 'Unknown skill' ;
4132const DEFAULT_LOCALE = 'en-US' ;
42- const SIMPLE_TZ_PATTERN = / ^ [ A - Z a - z ] { 2 , 6 } $ / ;
43- const OFFSET_TZ_PATTERN = / ^ (?: U T C | G M T ) ? \s * ( [ + - ] ) \s * ( \d { 1 , 2 } ) (?: : ? ( \d { 2 } ) ) ? $ / i;
44- const BARE_OFFSET_PATTERN = / ^ ( [ + - ] ) ( \d { 2 } ) (?: : ? ( \d { 2 } ) ) $ / ;
45- const TIMEZONE_ABBREVIATION_LONG_NAMES = {
46- ACDT : 'Australian Central Daylight Time' ,
47- ACST : 'Australian Central Standard Time' ,
48- AEDT : 'Australian Eastern Daylight Time' ,
49- AEST : 'Australian Eastern Standard Time' ,
50- AKDT : 'Alaska Daylight Time' ,
51- AKST : 'Alaska Standard Time' ,
52- AWST : 'Australian Western Standard Time' ,
53- BST : 'British Summer Time' ,
54- CDT : 'Central Daylight Time' ,
55- CEST : 'Central European Summer Time' ,
56- CET : 'Central European Standard Time' ,
57- CST : 'Central Standard Time' ,
58- EDT : 'Eastern Daylight Time' ,
59- EEST : 'Eastern European Summer Time' ,
60- EET : 'Eastern European Standard Time' ,
61- EST : 'Eastern Standard Time' ,
62- GMT : 'Greenwich Mean Time' ,
63- HST : 'Hawaii-Aleutian Standard Time' ,
64- IST : 'India Standard Time' ,
65- JST : 'Japan Standard Time' ,
66- KST : 'Korea Standard Time' ,
67- MDT : 'Mountain Daylight Time' ,
68- MST : 'Mountain Standard Time' ,
69- NZDT : 'New Zealand Daylight Time' ,
70- NZST : 'New Zealand Standard Time' ,
71- PDT : 'Pacific Daylight Time' ,
72- PST : 'Pacific Standard Time' ,
73- SAST : 'South Africa Standard Time' ,
74- UTC : 'Coordinated Universal Time' ,
75- WEST : 'Western European Summer Time' ,
76- WET : 'Western European Standard Time' ,
77- } ;
33+
7834const REGION_NAME_OVERRIDES = {
7935 UK : 'United Kingdom' ,
8036} ;
8137const regionDisplayNames = typeof Intl !== 'undefined' && typeof Intl . DisplayNames === 'function'
8238 ? new Intl . DisplayNames ( [ DEFAULT_LOCALE ] , { type : 'region' } )
8339 : null ;
84- let timezoneAbbreviationMap ;
8540
8641function asArray ( value ) {
8742 if ( ! value ) return [ ] ;
8843 return Array . isArray ( value ) ? value : [ value ] ;
8944}
9045
91- function isUuid ( value ) {
92- return typeof value === 'string' && UUID_PATTERN . test ( value ) ;
93- }
94-
9546function toTitleCase ( value ) {
9647 return value
9748 . toLowerCase ( )
@@ -127,21 +78,6 @@ function normalizeLabel(value, normalizedMap) {
12778 return spaced || raw ;
12879}
12980
130- function normalizeSkillLabel ( skill ) {
131- if ( ! skill ) return null ;
132-
133- if ( typeof skill === 'object' && skill !== null ) {
134- const label = skill . name || skill . title ;
135- if ( label ) return String ( label ) ;
136- const skillId = skill . id || skill . value ;
137- if ( isUuid ( skillId ) ) return UNKNOWN_SKILL_LABEL ;
138- return skillId ? String ( skillId ) : null ;
139- }
140-
141- if ( isUuid ( skill ) ) return UNKNOWN_SKILL_LABEL ;
142- return String ( skill ) ;
143- }
144-
14581function normalizeLocationValue ( value ) {
14682 if ( ! value ) return null ;
14783 if ( typeof value === 'object' && value !== null ) {
@@ -173,154 +109,6 @@ function normalizeRegionValue(value) {
173109 return trimmed ;
174110}
175111
176- function getIntlTimeZoneName ( timeZone , style ) {
177- if ( typeof Intl === 'undefined' || typeof Intl . DateTimeFormat !== 'function' ) {
178- return null ;
179- }
180-
181- try {
182- const formatter = new Intl . DateTimeFormat ( DEFAULT_LOCALE , {
183- timeZone,
184- timeZoneName : style ,
185- } ) ;
186-
187- if ( typeof formatter . formatToParts !== 'function' ) {
188- return null ;
189- }
190-
191- const parts = formatter . formatToParts ( new Date ( ) ) ;
192- const namePart = parts . find ( part => part . type === 'timeZoneName' ) ;
193- return namePart && namePart . value ? namePart . value : null ;
194- } catch ( error ) {
195- return null ;
196- }
197- }
198-
199- function getMomentTimeZoneName ( timeZone ) {
200- if ( ! moment || ! moment . tz || ! moment . tz . zone ) {
201- return null ;
202- }
203-
204- if ( ! moment . tz . zone ( timeZone ) ) {
205- return null ;
206- }
207-
208- try {
209- return moment . tz ( new Date ( ) , timeZone ) . format ( 'z' ) ;
210- } catch ( error ) {
211- return null ;
212- }
213- }
214-
215- function getTimeZoneAbbreviationMap ( ) {
216- if ( timezoneAbbreviationMap ) return timezoneAbbreviationMap ;
217- timezoneAbbreviationMap = new Map ( ) ;
218- if ( ! moment || ! moment . tz || typeof moment . tz . names !== 'function' ) {
219- return timezoneAbbreviationMap ;
220- }
221-
222- moment . tz . names ( ) . forEach ( ( zoneName ) => {
223- try {
224- const abbr = moment . tz ( new Date ( ) , zoneName ) . format ( 'z' ) ;
225- if ( ! abbr ) return ;
226- const normalized = abbr . toUpperCase ( ) ;
227- if ( ! timezoneAbbreviationMap . has ( normalized ) ) {
228- timezoneAbbreviationMap . set ( normalized , zoneName ) ;
229- }
230- } catch ( error ) {
231- // ignore invalid timezone data
232- }
233- } ) ;
234-
235- return timezoneAbbreviationMap ;
236- }
237-
238- function resolveTimeZoneAbbreviationName ( abbreviation ) {
239- const normalized = abbreviation . toUpperCase ( ) ;
240- if ( TIMEZONE_ABBREVIATION_LONG_NAMES [ normalized ] ) {
241- return TIMEZONE_ABBREVIATION_LONG_NAMES [ normalized ] ;
242- }
243-
244- const map = getTimeZoneAbbreviationMap ( ) ;
245- const zoneName = map . get ( normalized ) ;
246- if ( ! zoneName ) return null ;
247-
248- return (
249- getIntlTimeZoneName ( zoneName , 'long' )
250- || getIntlTimeZoneName ( zoneName , 'longGeneric' )
251- ) ;
252- }
253-
254- function formatUtcOffset ( sign , hours , minutes ) {
255- const hourValue = Number ( hours ) ;
256- const minuteValue = Number ( minutes || 0 ) ;
257-
258- if ( Number . isNaN ( hourValue ) || Number . isNaN ( minuteValue ) ) {
259- return null ;
260- }
261-
262- const normalizedHours = String ( Math . abs ( hourValue ) ) . padStart ( 2 , '0' ) ;
263- const normalizedMinutes = String ( Math . abs ( minuteValue ) ) . padStart ( 2 , '0' ) ;
264- const suffix = normalizedMinutes !== '00' ? `:${ normalizedMinutes } ` : '' ;
265-
266- return `UTC${ sign } ${ normalizedHours } ${ suffix } ` ;
267- }
268-
269- function normalizeUtcOffset ( value ) {
270- if ( ! value ) return null ;
271- const normalized = String ( value ) . trim ( ) ;
272- if ( ! normalized ) return null ;
273-
274- if ( / ^ ( u t c | g m t ) $ / i. test ( normalized ) ) {
275- return 'UTC' ;
276- }
277-
278- const offsetMatch = normalized . match ( OFFSET_TZ_PATTERN ) ;
279- if ( offsetMatch ) {
280- return formatUtcOffset ( offsetMatch [ 1 ] , offsetMatch [ 2 ] , offsetMatch [ 3 ] ) ;
281- }
282-
283- const bareMatch = normalized . match ( BARE_OFFSET_PATTERN ) ;
284- if ( bareMatch ) {
285- return formatUtcOffset ( bareMatch [ 1 ] , bareMatch [ 2 ] , bareMatch [ 3 ] ) ;
286- }
287-
288- return null ;
289- }
290-
291- function normalizeTimezoneValue ( value ) {
292- const normalizedValue = normalizeLocationValue ( value ) ;
293- if ( ! normalizedValue ) return null ;
294-
295- const trimmed = normalizedValue . trim ( ) ;
296- if ( ! trimmed ) return null ;
297-
298- if ( trimmed . toLowerCase ( ) === 'any' ) {
299- return 'Any' ;
300- }
301-
302- const longName = getIntlTimeZoneName ( trimmed , 'long' ) || getIntlTimeZoneName ( trimmed , 'longGeneric' ) ;
303- if ( longName ) {
304- return longName ;
305- }
306-
307- const offset = normalizeUtcOffset ( trimmed ) ;
308- if ( offset ) {
309- return offset ;
310- }
311-
312- if ( SIMPLE_TZ_PATTERN . test ( trimmed ) ) {
313- return resolveTimeZoneAbbreviationName ( trimmed ) || trimmed . toUpperCase ( ) ;
314- }
315-
316- const fallbackShortName = getMomentTimeZoneName ( trimmed ) || getIntlTimeZoneName ( trimmed , 'short' ) ;
317- if ( fallbackShortName ) {
318- return fallbackShortName ;
319- }
320-
321- return trimmed ;
322- }
323-
324112function uniqNormalizedStrings ( values ) {
325113 const seen = new Set ( ) ;
326114 return values . reduce ( ( acc , value ) => {
@@ -365,10 +153,6 @@ function getWorkloadDisplay(workload) {
365153 return normalizeLabel ( workload , WORKLOAD_LABELS ) ;
366154}
367155
368- function getAnticipatedStartDisplay ( value ) {
369- return normalizeLabel ( value , ANTICIPATED_START_LABELS ) ;
370- }
371-
372156function getCompensationDisplay ( compensationRange ) {
373157 if ( typeof compensationRange === 'object' && compensationRange !== null ) {
374158 const label = compensationRange . name || compensationRange . title ;
@@ -406,17 +190,10 @@ function EngagementCard({ engagement }) {
406190 role,
407191 workload,
408192 compensationRange,
409- skills : engagementSkills ,
410- requiredSkills,
411- skillsets,
412193 location,
413194 locations : engagementLocations ,
414- timezone,
415- timezones,
416- timeZones,
417195 countries,
418196 status,
419- anticipatedStart,
420197 nanoId,
421198 id,
422199 engagementId,
@@ -431,44 +208,18 @@ function EngagementCard({ engagement }) {
431208 durationWeeks ,
432209 durationMonths ,
433210 ) ;
434- const anticipatedStartText = getAnticipatedStartDisplay ( anticipatedStart ) ;
435-
436- const skillsSource = [ engagementSkills , requiredSkills , skillsets ]
437- . find ( value => Array . isArray ( value ) && value . length )
438- || engagementSkills
439- || requiredSkills
440- || skillsets ;
441- const skills = Array . from ( new Set (
442- asArray ( skillsSource )
443- . map ( normalizeSkillLabel )
444- . filter ( Boolean ) ,
445- ) ) ;
446- const skillsText = skills . length
447- ? skills . slice ( 0 , 2 ) . join ( ', ' )
448- : 'Not Specified' ;
449- const limitedSkillsText = skills . length > 2
450- ? `${ skillsText } ,...`
451- : skillsText ;
452211
453212 const baseLocations = [
454213 ...asArray ( location ) ,
455214 ...asArray ( engagementLocations ) ,
456215 ]
457216 . map ( normalizeRegionValue )
458217 . filter ( Boolean ) ;
459- const timezoneValues = [
460- ...asArray ( timezone ) ,
461- ...asArray ( timezones ) ,
462- ...asArray ( timeZones ) ,
463- ]
464- . map ( normalizeTimezoneValue )
465- . filter ( Boolean ) ;
466218 const countryValues = asArray ( countries )
467219 . map ( normalizeRegionValue )
468220 . filter ( Boolean ) ;
469221 const isAnyValue = value => value . trim ( ) . toLowerCase ( ) === 'any' ;
470222 const hasAnyLocation = [ ...baseLocations , ...countryValues ] . some ( isAnyValue ) ;
471- const hasAnyTimezone = timezoneValues . some ( isAnyValue ) ;
472223 const filteredBaseLocations = baseLocations . filter ( value => ! isAnyValue ( value ) ) ;
473224 const filteredCountries = countryValues . filter ( value => ! isAnyValue ( value ) ) ;
474225 const locations = uniqNormalizedStrings ( [
@@ -477,15 +228,6 @@ function EngagementCard({ engagement }) {
477228 ...filteredCountries ,
478229 ] ) ;
479230 const locationText = locations . length ? locations . join ( ', ' ) : 'Remote' ;
480- const filteredTimezones = uniqNormalizedStrings (
481- timezoneValues . filter ( value => ! isAnyValue ( value ) ) ,
482- ) ;
483- let timezoneText = 'Not Specified' ;
484- if ( filteredTimezones . length ) {
485- timezoneText = filteredTimezones . join ( ', ' ) ;
486- } else if ( hasAnyTimezone ) {
487- timezoneText = 'Any' ;
488- }
489231
490232 const resolvedEngagementId = nanoId || id || engagementId ;
491233 const engagementLink = resolvedEngagementId
@@ -505,12 +247,6 @@ function EngagementCard({ engagement }) {
505247 < div styleName = "icon-val" >
506248 < img src = { iconBlackSkills } alt = "role-icon" /> { getRoleDisplay ( role ) }
507249 </ div >
508- < div styleName = "icon-val" >
509- < img src = { iconBlackSkills } alt = "skills-icon" /> { limitedSkillsText }
510- </ div >
511- < div styleName = "icon-val" >
512- < IconTimezone /> { timezoneText }
513- </ div >
514250 < div styleName = "icon-val" >
515251 < IconBlackLocation /> { locationText }
516252 </ div >
@@ -523,9 +259,6 @@ function EngagementCard({ engagement }) {
523259 < div styleName = "icon-val" >
524260 < IconBlackDuration /> { durationText }
525261 </ div >
526- < div styleName = "icon-val" >
527- < IconBlackDuration /> { `Anticipated start: ${ anticipatedStartText } ` }
528- </ div >
529262 < div styleName = "row-btn" >
530263 < a styleName = "primary-green-md" href = { engagementLink } >
531264 VIEW DETAILS
0 commit comments