• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Problematy / goodmap / 28131466663

24 Jun 2026 09:41PM UTC coverage: 74.158%. First build
28131466663

Pull #365

github

web-flow
Merge 6f4f8c15d into 27cbf5bb0
Pull Request #365: refactor!: aligned with breaking changes on platzky

174 of 277 branches covered (62.82%)

Branch coverage included in aggregate %.

575 of 733 new or added lines in 26 files covered. (78.44%)

575 of 733 relevant lines covered (78.44%)

8.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.76
/frontend/src/components/MarkerPopup/mapCustomTypeToReactComponent.jsx
1
import React from 'react';
2
import { MarkerCTAButtonStyle } from '../../styles/buttonStyle';
3
import PluginSlot from '../../plugins/PluginSlot';
4

5
/**
6
 * Converts data to a string representation.
7
 * Arrays are joined with comma-space separator, other values are converted to string.
8
 *
9
 * @param {*} data - Data to convert to string
10
 * @returns {string} Joined string if array, otherwise the data converted to string
11
 */
12
export const getContentAsString = data =>
6✔
13
    Array.isArray(data) ? data.join(', ') : String(data ?? '');
41!
14

15
/**
16
 * Sanitizes URLs to prevent javascript: or data: injection attacks.
17
 * Only allows http:, https:, mailto:, and tel: protocols.
18
 *
19
 * @param {*} raw - Raw URL to sanitize
20
 * @returns {string|null} Sanitized URL or null if invalid/unsafe
21
 */
22
const sanitizeUrl = raw => {
6✔
23
    try {
26✔
24
        // Use globalThis.location.origin as base, with fallback for non-browser environments
25
        const base = globalThis.location?.origin || 'http://localhost';
26!
26
        const url = new URL(String(raw), base);
26✔
27
        const allowed = new Set(['http:', 'https:', 'mailto:', 'tel:']);
26✔
28
        return allowed.has(url.protocol) ? url.href : null;
26!
29
    } catch {
NEW
30
        return null;
×
31
    }
32
};
33

34
/**
35
 * Maps custom typed values to appropriate React components.
36
 * Supports hyperlinks and CTA (Call-To-Action) buttons.
37
 *
38
 * @param {Object} customValue - Custom value object with type and value properties
39
 * @param {string} customValue.type - Type of custom value ('hyperlink' or 'CTA')
40
 * @param {string} customValue.value - URL or value to use
41
 * @param {string} [customValue.displayValue] - Optional display text (falls back to value)
42
 * @returns {React.ReactElement|string} React component for the custom type or string content
43
 */
44
export const mapCustomTypeToReactComponent = customValue => {
6✔
45
    if (customValue.scope) {
41✔
46
        const { scope, ...props } = customValue;
1✔
47
        return <PluginSlot scope={scope} props={props} />;
1✔
48
    }
49

50
    if (!customValue.type || !customValue.value) {
40✔
51
        return getContentAsString(customValue);
1✔
52
    }
53

54
    const valueToDisplay = customValue?.displayValue || customValue.value;
39✔
55

56
    switch (customValue.type) {
39✔
57
        case 'hyperlink': {
58
            const safe = sanitizeUrl(customValue.value);
25✔
59
            if (!safe) return valueToDisplay;
25!
60
            return (
25✔
61
                <a href={safe} rel="noreferrer noopener" target="_blank">
62
                    {valueToDisplay}
63
                </a>
64
            );
65
        }
66
        case 'CTA': {
67
            const handleRedirect = () => {
2✔
68
                const safe = sanitizeUrl(customValue.value);
1✔
69
                if (!safe) return;
1!
70
                globalThis.open(safe, '_blank');
1✔
71
            };
72
            return (
2✔
73
                <button
74
                    type="button"
75
                    onClick={handleRedirect}
76
                    style={MarkerCTAButtonStyle}
77
                    data-variant="contained"
78
                >
79
                    {valueToDisplay}
80
                </button>
81
            );
82
        }
83
        default:
84
            return getContentAsString(valueToDisplay);
12✔
85
    }
86
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc