@xyo-network/react-xns 3.0.11 → 3.0.13
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.
- package/dist/browser/components/XnsNameCapture/Props.d.ts +2 -1
- package/dist/browser/components/XnsNameCapture/Props.d.ts.map +1 -1
- package/dist/browser/components/XnsNameCapture/hooks/index.d.ts +1 -1
- package/dist/browser/components/XnsNameCapture/hooks/index.d.ts.map +1 -1
- package/dist/browser/components/XnsNameCapture/hooks/routing/index.d.ts +3 -0
- package/dist/browser/components/XnsNameCapture/hooks/routing/index.d.ts.map +1 -0
- package/dist/browser/components/XnsNameCapture/hooks/{useXnsNameCaptureRouting.d.ts → routing/useXnsNameCaptureRouting.d.ts} +4 -3
- package/dist/browser/components/XnsNameCapture/hooks/{useXnsNameCaptureRouting.d.ts.map → routing/useXnsNameCaptureRouting.d.ts.map} +1 -1
- package/dist/browser/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.d.ts +2 -0
- package/dist/browser/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.d.ts.map +1 -0
- package/dist/browser/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.d.ts +2 -1
- package/dist/browser/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.d.ts.map +1 -1
- package/dist/browser/index.mjs +72 -31
- package/dist/browser/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/XnsNameCapture/Props.ts +2 -1
- package/src/components/XnsNameCapture/SecondaryLink.stories.tsx +1 -1
- package/src/components/XnsNameCapture/SecondaryLink.tsx +2 -2
- package/src/components/XnsNameCapture/XnsNameCapture.stories.tsx +1 -1
- package/src/components/XnsNameCapture/XnsNameCapture.tsx +12 -12
- package/src/components/XnsNameCapture/XnsNameCaptureWithContext.stories.tsx +35 -9
- package/src/components/XnsNameCapture/hooks/index.ts +1 -1
- package/src/components/XnsNameCapture/hooks/routing/index.ts +2 -0
- package/src/components/XnsNameCapture/hooks/{useXnsNameCaptureRouting.ts → routing/useXnsNameCaptureRouting.ts} +6 -1
- package/src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts +26 -0
|
@@ -4,7 +4,7 @@ import type { Mixpanel } from 'mixpanel-browser';
|
|
|
4
4
|
import type { ReactNode } from 'react';
|
|
5
5
|
import type { To } from 'react-router-dom';
|
|
6
6
|
export interface XnsNameCaptureBuyCallbacks {
|
|
7
|
-
|
|
7
|
+
onCaptureName?: (name: string) => Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export interface XnsNameCaptureTrackingProps {
|
|
10
10
|
event?: string;
|
|
@@ -15,6 +15,7 @@ export interface XnsNameCaptureTrackingProps {
|
|
|
15
15
|
export interface XnsNameCaptureRoutingProps {
|
|
16
16
|
navigate?: (to: string) => void;
|
|
17
17
|
paramsString?: string;
|
|
18
|
+
routingError?: Error;
|
|
18
19
|
to?: To;
|
|
19
20
|
}
|
|
20
21
|
export interface XnsNameCaptureBaseProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Props.d.ts","sourceRoot":"","sources":["../../../../src/components/XnsNameCapture/Props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAE1C,MAAM,WAAW,0BAA0B;IACzC,
|
|
1
|
+
{"version":3,"file":"Props.d.ts","sourceRoot":"","sources":["../../../../src/components/XnsNameCapture/Props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAE1C,MAAM,WAAW,0BAA0B;IACzC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAChD;AAKD,MAAM,WAAW,2BAA2B;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,UAAU,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACvD;AAKD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB,EAAE,CAAC,EAAE,EAAE,CAAA;CACR;AAKD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACpC;AAED,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB,EAClE,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,YAAY;CACZ;AAEF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAA;CAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/XnsNameCapture/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/XnsNameCapture/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,iCAAiC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/XnsNameCapture/hooks/routing/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,6BAA6B,CAAA"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { XnsNameCaptureProps } from '
|
|
1
|
+
import type { XnsNameCaptureProps } from '../../Props.ts';
|
|
2
2
|
export declare const useXnsNameCaptureRouting: (props: XnsNameCaptureProps) => {
|
|
3
|
+
defaultXnsName: string | undefined;
|
|
4
|
+
routingError: Error | undefined;
|
|
3
5
|
navigate: (to: string) => void;
|
|
4
6
|
paramsString: string;
|
|
5
7
|
autoFocus?: boolean;
|
|
6
8
|
buttonText?: string;
|
|
7
|
-
defaultXnsName?: string;
|
|
8
9
|
errorUi?: "alert" | "toast";
|
|
9
10
|
mobileButtonText?: string;
|
|
10
11
|
placement?: string;
|
|
@@ -13,7 +14,7 @@ export declare const useXnsNameCaptureRouting: (props: XnsNameCaptureProps) => {
|
|
|
13
14
|
funnel?: string;
|
|
14
15
|
mixpanel?: import("mixpanel-browser").Mixpanel;
|
|
15
16
|
userEvents?: import("@xylabs/pixel").UserEventHandler<Record<string, unknown>>;
|
|
16
|
-
|
|
17
|
+
onCaptureName?: (name: string) => Promise<void>;
|
|
17
18
|
to?: import("react-router-dom").To;
|
|
18
19
|
background?: boolean;
|
|
19
20
|
paper?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useXnsNameCaptureRouting.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"useXnsNameCaptureRouting.d.ts","sourceRoot":"","sources":["../../../../../../src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAGzD,eAAO,MAAM,wBAAwB,UAAW,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBlE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useXnsNameFromLocation.d.ts","sourceRoot":"","sources":["../../../../../../src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,sBAAsB,QAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAmB5F,CAAA"}
|
|
@@ -11,9 +11,10 @@ export declare const useXnsNameCaptureProviders: (props: XnsNameCaptureProps) =>
|
|
|
11
11
|
event?: string;
|
|
12
12
|
funnel?: string;
|
|
13
13
|
userEvents?: import("@xylabs/pixel").UserEventHandler<Record<string, unknown>>;
|
|
14
|
-
|
|
14
|
+
onCaptureName?: (name: string) => Promise<void>;
|
|
15
15
|
navigate?: (to: string) => void;
|
|
16
16
|
paramsString?: string;
|
|
17
|
+
routingError?: Error;
|
|
17
18
|
to?: import("react-router").To;
|
|
18
19
|
background?: boolean;
|
|
19
20
|
paper?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useXnsNameCaptureProviders.d.ts","sourceRoot":"","sources":["../../../../../src/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD,eAAO,MAAM,0BAA0B,UAAW,mBAAmB
|
|
1
|
+
{"version":3,"file":"useXnsNameCaptureProviders.d.ts","sourceRoot":"","sources":["../../../../../src/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEtD,eAAO,MAAM,0BAA0B,UAAW,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAOpE,CAAA"}
|
package/dist/browser/index.mjs
CHANGED
|
@@ -77,30 +77,56 @@ var XnsNameCaptureErrors = /* @__PURE__ */ __name(({ error, errorUi, resetError
|
|
|
77
77
|
})());
|
|
78
78
|
}, "XnsNameCaptureErrors");
|
|
79
79
|
|
|
80
|
-
// src/components/XnsNameCapture/hooks/
|
|
81
|
-
import { useMixpanel } from "@xylabs/react-mixpanel";
|
|
80
|
+
// src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts
|
|
82
81
|
import { useMemo } from "react";
|
|
83
|
-
var useXnsNameCaptureProviders = /* @__PURE__ */ __name((props) => {
|
|
84
|
-
const mixpanel = useMixpanel();
|
|
85
|
-
return useMemo(() => ({
|
|
86
|
-
...props,
|
|
87
|
-
mixpanel: props.mixpanel ?? mixpanel
|
|
88
|
-
}), [
|
|
89
|
-
props,
|
|
90
|
-
mixpanel
|
|
91
|
-
]);
|
|
92
|
-
}, "useXnsNameCaptureProviders");
|
|
93
|
-
|
|
94
|
-
// src/components/XnsNameCapture/hooks/useXnsNameCaptureRouting.ts
|
|
95
|
-
import { useMemo as useMemo2 } from "react";
|
|
96
82
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
|
83
|
+
|
|
84
|
+
// src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts
|
|
85
|
+
import { useLocation } from "react-router-dom";
|
|
86
|
+
var useXnsNameFromLocation = /* @__PURE__ */ __name(() => {
|
|
87
|
+
const location = useLocation();
|
|
88
|
+
const search = new URLSearchParams(location.search);
|
|
89
|
+
const rawName = (search.get("xnsname") ?? search.get("name") ?? search.get("username") ?? "").toLowerCase();
|
|
90
|
+
switch (rawName?.split(".").length) {
|
|
91
|
+
case 1: {
|
|
92
|
+
return [
|
|
93
|
+
rawName,
|
|
94
|
+
void 0
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
case 2: {
|
|
98
|
+
const rawNameParts = rawName.split(".");
|
|
99
|
+
if (rawNameParts[1] !== "xyo") {
|
|
100
|
+
return [
|
|
101
|
+
,
|
|
102
|
+
new Error("Invalid xNS name [Bad root]")
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
return [
|
|
106
|
+
rawNameParts[0],
|
|
107
|
+
void 0
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
default: {
|
|
111
|
+
return [
|
|
112
|
+
,
|
|
113
|
+
new Error("Invalid xNS name [Too many parts]")
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}, "useXnsNameFromLocation");
|
|
118
|
+
|
|
119
|
+
// src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts
|
|
97
120
|
var useXnsNameCaptureRouting = /* @__PURE__ */ __name((props) => {
|
|
98
121
|
const [params] = useSearchParams();
|
|
99
122
|
const signatureParam = params.get("signature");
|
|
100
123
|
const signatureParamString = signatureParam ? `&signature=${encodeURIComponent(signatureParam)}` : "";
|
|
101
124
|
const navigate = useNavigate();
|
|
102
|
-
|
|
125
|
+
const [name, error] = useXnsNameFromLocation();
|
|
126
|
+
return useMemo(() => ({
|
|
103
127
|
...props,
|
|
128
|
+
defaultXnsName: name,
|
|
129
|
+
routingError: error,
|
|
104
130
|
navigate: props.navigate ?? ((to) => navigate(to)),
|
|
105
131
|
paramsString: signatureParamString
|
|
106
132
|
}), [
|
|
@@ -109,13 +135,27 @@ var useXnsNameCaptureRouting = /* @__PURE__ */ __name((props) => {
|
|
|
109
135
|
]);
|
|
110
136
|
}, "useXnsNameCaptureRouting");
|
|
111
137
|
|
|
138
|
+
// src/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.ts
|
|
139
|
+
import { useMixpanel } from "@xylabs/react-mixpanel";
|
|
140
|
+
import { useMemo as useMemo2 } from "react";
|
|
141
|
+
var useXnsNameCaptureProviders = /* @__PURE__ */ __name((props) => {
|
|
142
|
+
const mixpanel = useMixpanel();
|
|
143
|
+
return useMemo2(() => ({
|
|
144
|
+
...props,
|
|
145
|
+
mixpanel: props.mixpanel ?? mixpanel
|
|
146
|
+
}), [
|
|
147
|
+
props,
|
|
148
|
+
mixpanel
|
|
149
|
+
]);
|
|
150
|
+
}, "useXnsNameCaptureProviders");
|
|
151
|
+
|
|
112
152
|
// src/components/XnsNameCapture/SecondaryLink.tsx
|
|
113
153
|
import { ArrowForwardRounded } from "@mui/icons-material";
|
|
114
154
|
import { Stack } from "@mui/material";
|
|
115
155
|
import { LinkEx } from "@xylabs/react-link";
|
|
116
156
|
import { XnsNameHelper as XnsNameHelper2 } from "@xyo-network/xns-record-payloadset-plugins";
|
|
117
157
|
import React3 from "react";
|
|
118
|
-
var XnsCaptureSecondaryLink = /* @__PURE__ */ __name(({ event = "Click to Reservation", funnel = "xns", mixpanel, navigate,
|
|
158
|
+
var XnsCaptureSecondaryLink = /* @__PURE__ */ __name(({ event = "Click to Reservation", funnel = "xns", mixpanel, navigate, onCaptureName, paramsString = "", placement = "", setError, text = "Or make a free reservation", to = "/xns/reservation", userEvents, xnsName, ...props }) => {
|
|
119
159
|
return /* @__PURE__ */ React3.createElement(LinkEx, {
|
|
120
160
|
paddingX: 0,
|
|
121
161
|
color: "inherit",
|
|
@@ -137,7 +177,7 @@ var XnsCaptureSecondaryLink = /* @__PURE__ */ __name(({ event = "Click to Reserv
|
|
|
137
177
|
elementType: "xns-cta"
|
|
138
178
|
});
|
|
139
179
|
navigate?.(`${to}?username=${xnsName}${paramsString}`);
|
|
140
|
-
await
|
|
180
|
+
await onCaptureName?.(xnsName);
|
|
141
181
|
} else {
|
|
142
182
|
setError?.(new Error(errors.join(", ")));
|
|
143
183
|
}
|
|
@@ -160,19 +200,19 @@ import { ButtonEx } from "@xylabs/react-button";
|
|
|
160
200
|
import { FlexCol, FlexRow as FlexRow2 } from "@xylabs/react-flexbox";
|
|
161
201
|
import { MIN_DOMAIN_LENGTH as MIN_DOMAIN_LENGTH2, XnsNameHelper as XnsNameHelper3 } from "@xyo-network/xns-record-payloadset-plugins";
|
|
162
202
|
import React4, { useCallback, useState as useState2 } from "react";
|
|
163
|
-
var XnsNameCapture = /* @__PURE__ */ __name(({ autoFocus = false, buttonText = "Buy My Name", children, defaultXnsName, errorUi = "alert", event = "Click to Checkout", funnel = "xns", mixpanel, mobileButtonText = "Buy", navigate,
|
|
203
|
+
var XnsNameCapture = /* @__PURE__ */ __name(({ autoFocus = false, buttonText = "Buy My Name", children, defaultXnsName, errorUi = "alert", event = "Click to Checkout", funnel = "xns", mixpanel, mobileButtonText = "Buy", navigate, onCaptureName: onCaptureNameProp, paramsString = "", placement = "", routingError, showSecondary = false, to = "/xns/estimation", userEvents, ...props }) => {
|
|
164
204
|
const [xnsName, setXnsName] = useState2(() => defaultXnsName ?? "");
|
|
165
|
-
const [error, setError] = useState2();
|
|
205
|
+
const [error, setError] = useState2(routingError);
|
|
166
206
|
const theme = useTheme3();
|
|
167
207
|
const isMobile = useMediaQuery2(theme.breakpoints.down("md"));
|
|
168
|
-
const
|
|
208
|
+
const captureDisabled = !xnsName || xnsName.length < MIN_DOMAIN_LENGTH2;
|
|
169
209
|
const handleChange = /* @__PURE__ */ __name((event2) => {
|
|
170
210
|
const NsName = XnsNameHelper3.mask(event2.target.value);
|
|
171
211
|
setXnsName(NsName);
|
|
172
212
|
setError(void 0);
|
|
173
213
|
}, "handleChange");
|
|
174
|
-
const
|
|
175
|
-
if (
|
|
214
|
+
const onCaptureName = useCallback(async () => {
|
|
215
|
+
if (captureDisabled) return;
|
|
176
216
|
mixpanel?.track(event, {
|
|
177
217
|
Funnel: funnel,
|
|
178
218
|
Placement: placement
|
|
@@ -185,7 +225,7 @@ var XnsNameCapture = /* @__PURE__ */ __name(({ autoFocus = false, buttonText = "
|
|
|
185
225
|
elementName: event,
|
|
186
226
|
elementType: "xns-cta"
|
|
187
227
|
});
|
|
188
|
-
await
|
|
228
|
+
await onCaptureNameProp?.(xnsName);
|
|
189
229
|
navigate?.(`${to}?username=${xnsName}${paramsString}`);
|
|
190
230
|
} else {
|
|
191
231
|
setError(new Error(errors.join(", ")));
|
|
@@ -201,12 +241,12 @@ var XnsNameCapture = /* @__PURE__ */ __name(({ autoFocus = false, buttonText = "
|
|
|
201
241
|
xnsName
|
|
202
242
|
]);
|
|
203
243
|
const onKeyDown = useCallback(async (event2) => {
|
|
204
|
-
if (event2.key === "Enter" && !
|
|
205
|
-
await
|
|
244
|
+
if (event2.key === "Enter" && !captureDisabled) {
|
|
245
|
+
await onCaptureName?.();
|
|
206
246
|
}
|
|
207
247
|
}, [
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
captureDisabled,
|
|
249
|
+
onCaptureName
|
|
210
250
|
]);
|
|
211
251
|
return /* @__PURE__ */ React4.createElement(
|
|
212
252
|
FlexCol,
|
|
@@ -227,11 +267,11 @@ var XnsNameCapture = /* @__PURE__ */ __name(({ autoFocus = false, buttonText = "
|
|
|
227
267
|
onChange: handleChange,
|
|
228
268
|
onBlur: handleChange
|
|
229
269
|
}), /* @__PURE__ */ React4.createElement(ButtonEx, {
|
|
230
|
-
disabled:
|
|
270
|
+
disabled: captureDisabled,
|
|
231
271
|
variant: "contained",
|
|
232
272
|
color: "success",
|
|
233
273
|
endIcon: /* @__PURE__ */ React4.createElement(KeyboardArrowRightRounded, null),
|
|
234
|
-
onClick:
|
|
274
|
+
onClick: onCaptureName
|
|
235
275
|
}, isMobile ? mobileButtonText : buttonText)),
|
|
236
276
|
showSecondary === true ? /* @__PURE__ */ React4.createElement(XnsCaptureSecondaryLink, {
|
|
237
277
|
xnsName,
|
|
@@ -271,6 +311,7 @@ export {
|
|
|
271
311
|
XnsNameCaptureErrors,
|
|
272
312
|
XnsNameCaptureWithContext,
|
|
273
313
|
useXnsNameCaptureProviders,
|
|
274
|
-
useXnsNameCaptureRouting
|
|
314
|
+
useXnsNameCaptureRouting,
|
|
315
|
+
useXnsNameFromLocation
|
|
275
316
|
};
|
|
276
317
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/EstimateName/EstimateNameTextField.tsx","../../src/components/XnsNameCapture/Errors.tsx","../../src/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.ts","../../src/components/XnsNameCapture/hooks/useXnsNameCaptureRouting.ts","../../src/components/XnsNameCapture/SecondaryLink.tsx","../../src/components/XnsNameCapture/XnsNameCapture.tsx","../../src/components/XnsNameCapture/XnsNameCaptureWithContext.tsx"],"sourcesContent":["import type { StandardTextFieldProps, TextFieldProps } from '@mui/material'\nimport {\n alpha, TextField, useTheme,\n} from '@mui/material'\nimport { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport React, { useState } from 'react'\n\nexport interface XnsEstimateNameTextFieldProps {\n maskOutput?: boolean\n}\n\nexport const XnsEstimateNameTextField: React.FC<XnsEstimateNameTextFieldProps & TextFieldProps> = ({\n maskOutput = true, onChange: onChangeProp, onBlur: onBlurProp, ...props\n}) => {\n const theme = useTheme()\n const [validLength, setValidLength] = useState(false)\n\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n // override onChange to mask the input and update the event value\n const handleChange: StandardTextFieldProps['onChange'] = (event) => {\n if (maskOutput) {\n const value = event.target.value\n event.target.value = XnsNameHelper.mask(value)\n }\n onChangeProp?.(event)\n\n if (inputRef.current) {\n setValidLength(inputRef.current.value.length >= MIN_DOMAIN_LENGTH)\n }\n }\n\n const handleBlur: StandardTextFieldProps['onBlur'] = (event) => {\n if (maskOutput) {\n const value = event.target.value\n event.target.value = XnsNameHelper.mask(value, { maskStartEndHyphens: true })\n }\n onBlurProp?.(event)\n }\n\n return (\n <TextField\n inputProps={{ style: { color: validLength ? theme.palette.text.primary : alpha(theme.palette.text.primary, 0.5) } }}\n inputRef={inputRef}\n onBlur={handleBlur}\n onChange={handleChange}\n {...props}\n />\n )\n}\n","import {\n Alert, Snackbar, useMediaQuery, useTheme,\n} from '@mui/material'\nimport { FlexRow } from '@xylabs/react-flexbox'\nimport React from 'react'\n\nexport interface XnsNameCaptureErrorsProps {\n error?: Error\n errorUi?: 'alert' | 'toast'\n resetError?: () => void\n}\n\nexport const XnsNameCaptureErrors: React.FC<XnsNameCaptureErrorsProps> = ({\n error, errorUi, resetError,\n}) => {\n const theme = useTheme()\n const isMobile = useMediaQuery(theme.breakpoints.down('md'))\n\n return (\n <>\n {(errorUi === 'toast')\n ? (\n <Snackbar\n open={!!error}\n message={error?.toString()}\n autoHideDuration={3000}\n onClose={() => resetError?.()}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <Alert\n severity=\"error\"\n sx={{\n width: '100%', display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden',\n }}\n >\n {error?.message}\n </Alert>\n </Snackbar>\n )\n : (() => {\n // setTimeout(() => setError(undefined), 1500)\n return (\n <FlexRow alignSelf=\"stretch\">\n <Alert\n severity=\"error\"\n sx={{ display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden' }}\n >\n {error?.message}\n </Alert>\n </FlexRow>\n )\n })()}\n </>\n )\n}\n","import { useMixpanel } from '@xylabs/react-mixpanel'\nimport { useMemo } from 'react'\n\nimport type { XnsNameCaptureProps } from '../Props.ts'\n\nexport const useXnsNameCaptureProviders = (props: XnsNameCaptureProps) => {\n const mixpanel = useMixpanel()\n\n return useMemo(() => ({\n ...props,\n mixpanel: props.mixpanel ?? mixpanel,\n }), [props, mixpanel])\n}\n","import { useMemo } from 'react'\nimport { useNavigate, useSearchParams } from 'react-router-dom'\n\nimport type { XnsNameCaptureProps } from '../Props.ts'\n\nexport const useXnsNameCaptureRouting = (props: XnsNameCaptureProps) => {\n const [params] = useSearchParams()\n const signatureParam = params.get('signature')\n const signatureParamString = signatureParam ? `&signature=${encodeURIComponent(signatureParam)}` : ''\n\n const navigate = useNavigate()\n\n return useMemo(() => ({\n ...props,\n navigate: props.navigate ?? ((to: string) => navigate(to)),\n paramsString: signatureParamString,\n }), [props, signatureParamString])\n}\n","import { ArrowForwardRounded } from '@mui/icons-material'\nimport { Stack } from '@mui/material'\nimport type { LinkExProps } from '@xylabs/react-link'\nimport { LinkEx } from '@xylabs/react-link'\nimport { XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport type { Dispatch } from 'react'\nimport React from 'react'\n\nimport type {\n XnsNameCaptureBuyCallbacks, XnsNameCaptureRoutingProps, XnsNameCaptureTrackingProps,\n} from './Props.ts'\n\nexport interface XnsCaptureSecondaryLinkProps extends XnsNameCaptureTrackingProps, XnsNameCaptureRoutingProps, XnsNameCaptureBuyCallbacks, LinkExProps {\n event?: string\n funnel?: string\n placement?: string\n setError?: Dispatch<Error | undefined>\n text?: string\n xnsName: string\n}\n\nexport const XnsCaptureSecondaryLink: React.FC<XnsCaptureSecondaryLinkProps> = ({\n event = 'Click to Reservation',\n funnel = 'xns',\n mixpanel,\n navigate,\n onBuyName,\n paramsString = '',\n placement = '',\n setError,\n text = 'Or make a free reservation',\n to = '/xns/reservation',\n userEvents,\n xnsName,\n ...props\n}) => {\n return (\n <LinkEx\n paddingX={0}\n color=\"inherit\"\n style={{ textDecoration: 'underline', textUnderlineOffset: '5px' }}\n onClick={async () => {\n mixpanel?.track(event, {\n Funnel: funnel,\n Placement: placement,\n })\n const formattedXnsName = `${xnsName}.xyo`\n const helper = XnsNameHelper.fromString(formattedXnsName)\n const [valid, errors] = await helper.validate()\n if (valid) {\n await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })\n navigate?.(`${to}?username=${xnsName}${paramsString}`)\n await onBuyName?.(xnsName)\n } else {\n setError?.(new Error(errors.join(', ')))\n }\n }}\n {...props}\n >\n <Stack flexDirection=\"row\" gap={0.5} alignItems=\"center\" sx={{ cursor: 'pointer' }}>\n {text}\n <ArrowForwardRounded />\n </Stack>\n </LinkEx>\n )\n}\n","import { KeyboardArrowRightRounded } from '@mui/icons-material'\nimport type { StandardTextFieldProps } from '@mui/material'\nimport { useMediaQuery, useTheme } from '@mui/material'\nimport { ButtonEx } from '@xylabs/react-button'\nimport { FlexCol, FlexRow } from '@xylabs/react-flexbox'\nimport { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport type { KeyboardEventHandler } from 'react'\nimport React, { useCallback, useState } from 'react'\n\nimport { XnsEstimateNameTextField } from '../EstimateName/index.ts'\nimport { XnsNameCaptureErrors } from './Errors.tsx'\nimport type { XnsNameCaptureProps } from './Props.ts'\nimport { XnsCaptureSecondaryLink } from './SecondaryLink.js'\n\nexport const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({\n autoFocus = false,\n buttonText = 'Buy My Name',\n children,\n defaultXnsName,\n errorUi = 'alert',\n event = 'Click to Checkout',\n funnel = 'xns',\n mixpanel,\n mobileButtonText = 'Buy',\n navigate,\n onBuyName: onBuyNameProp,\n paramsString = '',\n placement = '',\n showSecondary = false,\n to = '/xns/estimation',\n userEvents,\n ...props\n}) => {\n const [xnsName, setXnsName] = useState<string>(() => defaultXnsName ?? '')\n const [error, setError] = useState<Error | undefined>()\n\n const theme = useTheme()\n const isMobile = useMediaQuery(theme.breakpoints.down('md'))\n\n const buyDisabled = !xnsName || xnsName.length < MIN_DOMAIN_LENGTH\n\n const handleChange: StandardTextFieldProps['onChange'] = (event) => {\n const NsName = XnsNameHelper.mask(event.target.value)\n setXnsName(NsName)\n setError(undefined)\n }\n\n const onBuyName = useCallback(async () => {\n if (!xnsName) return\n\n mixpanel?.track(event, {\n Funnel: funnel,\n Placement: placement,\n })\n const formattedXnsName = `${xnsName}.xyo`\n const helper = XnsNameHelper.fromString(formattedXnsName)\n const [valid, errors] = await helper.validate()\n if (valid) {\n await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })\n await onBuyNameProp?.(xnsName)\n navigate?.(`${to}?username=${xnsName}${paramsString}`)\n } else {\n setError(new Error(errors.join(', ')))\n }\n }, [event, funnel, mixpanel, paramsString, placement, to, userEvents, xnsName])\n\n const onKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(async (event) => {\n if (event.key === 'Enter' && !buyDisabled) {\n await onBuyName?.()\n }\n }, [buyDisabled, onBuyName])\n\n return (\n <FlexCol gap={showSecondary ? 1.5 : 0} alignItems=\"center\" {...props}>\n <FlexRow gap={1}>\n <XnsEstimateNameTextField\n autoFocus={autoFocus}\n label=\"xNS Name\"\n variant=\"outlined\"\n size=\"small\"\n value={xnsName ?? ''}\n onKeyDown={onKeyDown}\n onChange={handleChange}\n onBlur={handleChange}\n />\n <ButtonEx\n disabled={buyDisabled}\n variant=\"contained\"\n color=\"success\"\n endIcon={<KeyboardArrowRightRounded />}\n onClick={onBuyName}\n >\n {isMobile ? mobileButtonText : buttonText}\n </ButtonEx>\n </FlexRow>\n {(showSecondary === true)\n ? (\n <XnsCaptureSecondaryLink\n xnsName={xnsName}\n placement={placement}\n funnel={funnel}\n setError={setError}\n />\n )\n : null}\n {\n // eslint-disable-next-line unicorn/prefer-logical-operator-over-ternary\n showSecondary ? showSecondary : null\n }\n {children}\n <XnsNameCaptureErrors error={error} errorUi={errorUi} resetError={() => setError(undefined)} />\n </FlexCol>\n )\n}\n","import React, { useMemo } from 'react'\n\nimport { useXnsNameCaptureProviders, useXnsNameCaptureRouting } from './hooks/index.ts'\nimport type { XnsNameCaptureProps } from './Props.ts'\nimport { XnsNameCapture } from './XnsNameCapture.tsx'\n\nexport const XnsNameCaptureWithContext: React.FC<XnsNameCaptureProps> = (props) => {\n const routingProps = useXnsNameCaptureRouting(props)\n const providersProps = useXnsNameCaptureProviders(routingProps)\n\n const updatedProps = useMemo<XnsNameCaptureProps>(() => ({\n ...props,\n ...routingProps,\n ...providersProps,\n }), [providersProps])\n\n return (\n <XnsNameCapture {...updatedProps} />\n )\n}\n"],"mappings":"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","names":["alpha","TextField","useTheme","MIN_DOMAIN_LENGTH","XnsNameHelper","React","useState","XnsEstimateNameTextField","maskOutput","onChange","onChangeProp","onBlur","onBlurProp","props","theme","useTheme","validLength","setValidLength","useState","inputRef","React","useRef","handleChange","event","value","target","XnsNameHelper","mask","current","length","MIN_DOMAIN_LENGTH","handleBlur","maskStartEndHyphens","TextField","inputProps","style","color","palette","text","primary","alpha","Alert","Snackbar","useMediaQuery","useTheme","FlexRow","React","XnsNameCaptureErrors","error","errorUi","resetError","theme","useTheme","isMobile","useMediaQuery","breakpoints","down","React","Snackbar","open","message","toString","autoHideDuration","onClose","anchorOrigin","vertical","horizontal","Alert","severity","sx","width","display","undefined","visibility","FlexRow","alignSelf","useMixpanel","useMemo","useXnsNameCaptureProviders","props","mixpanel","useMixpanel","useMemo","useMemo","useNavigate","useSearchParams","useXnsNameCaptureRouting","props","params","useSearchParams","signatureParam","get","signatureParamString","encodeURIComponent","navigate","useNavigate","useMemo","to","paramsString","ArrowForwardRounded","Stack","LinkEx","XnsNameHelper","React","XnsCaptureSecondaryLink","event","funnel","mixpanel","navigate","onBuyName","paramsString","placement","setError","text","to","userEvents","xnsName","props","React","LinkEx","paddingX","color","style","textDecoration","textUnderlineOffset","onClick","track","Funnel","Placement","formattedXnsName","helper","XnsNameHelper","fromString","valid","errors","validate","userClick","elementName","elementType","Error","join","Stack","flexDirection","gap","alignItems","sx","cursor","ArrowForwardRounded","KeyboardArrowRightRounded","useMediaQuery","useTheme","ButtonEx","FlexCol","FlexRow","MIN_DOMAIN_LENGTH","XnsNameHelper","React","useCallback","useState","XnsNameCapture","autoFocus","buttonText","children","defaultXnsName","errorUi","event","funnel","mixpanel","mobileButtonText","navigate","onBuyName","onBuyNameProp","paramsString","placement","showSecondary","to","userEvents","props","xnsName","setXnsName","useState","error","setError","theme","useTheme","isMobile","useMediaQuery","breakpoints","down","buyDisabled","length","MIN_DOMAIN_LENGTH","handleChange","NsName","XnsNameHelper","mask","target","value","undefined","useCallback","track","Funnel","Placement","formattedXnsName","helper","fromString","valid","errors","validate","userClick","elementName","elementType","Error","join","onKeyDown","key","React","FlexCol","gap","alignItems","FlexRow","XnsEstimateNameTextField","label","variant","size","onChange","onBlur","ButtonEx","disabled","color","endIcon","KeyboardArrowRightRounded","onClick","XnsCaptureSecondaryLink","XnsNameCaptureErrors","resetError","React","useMemo","XnsNameCaptureWithContext","props","routingProps","useXnsNameCaptureRouting","providersProps","useXnsNameCaptureProviders","updatedProps","useMemo","React","XnsNameCapture"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/EstimateName/EstimateNameTextField.tsx","../../src/components/XnsNameCapture/Errors.tsx","../../src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts","../../src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts","../../src/components/XnsNameCapture/hooks/useXnsNameCaptureProviders.ts","../../src/components/XnsNameCapture/SecondaryLink.tsx","../../src/components/XnsNameCapture/XnsNameCapture.tsx","../../src/components/XnsNameCapture/XnsNameCaptureWithContext.tsx"],"sourcesContent":["import type { StandardTextFieldProps, TextFieldProps } from '@mui/material'\nimport {\n alpha, TextField, useTheme,\n} from '@mui/material'\nimport { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport React, { useState } from 'react'\n\nexport interface XnsEstimateNameTextFieldProps {\n maskOutput?: boolean\n}\n\nexport const XnsEstimateNameTextField: React.FC<XnsEstimateNameTextFieldProps & TextFieldProps> = ({\n maskOutput = true, onChange: onChangeProp, onBlur: onBlurProp, ...props\n}) => {\n const theme = useTheme()\n const [validLength, setValidLength] = useState(false)\n\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n // override onChange to mask the input and update the event value\n const handleChange: StandardTextFieldProps['onChange'] = (event) => {\n if (maskOutput) {\n const value = event.target.value\n event.target.value = XnsNameHelper.mask(value)\n }\n onChangeProp?.(event)\n\n if (inputRef.current) {\n setValidLength(inputRef.current.value.length >= MIN_DOMAIN_LENGTH)\n }\n }\n\n const handleBlur: StandardTextFieldProps['onBlur'] = (event) => {\n if (maskOutput) {\n const value = event.target.value\n event.target.value = XnsNameHelper.mask(value, { maskStartEndHyphens: true })\n }\n onBlurProp?.(event)\n }\n\n return (\n <TextField\n inputProps={{ style: { color: validLength ? theme.palette.text.primary : alpha(theme.palette.text.primary, 0.5) } }}\n inputRef={inputRef}\n onBlur={handleBlur}\n onChange={handleChange}\n {...props}\n />\n )\n}\n","import {\n Alert, Snackbar, useMediaQuery, useTheme,\n} from '@mui/material'\nimport { FlexRow } from '@xylabs/react-flexbox'\nimport React from 'react'\n\nexport interface XnsNameCaptureErrorsProps {\n error?: Error\n errorUi?: 'alert' | 'toast'\n resetError?: () => void\n}\n\nexport const XnsNameCaptureErrors: React.FC<XnsNameCaptureErrorsProps> = ({\n error, errorUi, resetError,\n}) => {\n const theme = useTheme()\n const isMobile = useMediaQuery(theme.breakpoints.down('md'))\n\n return (\n <>\n {(errorUi === 'toast')\n ? (\n <Snackbar\n open={!!error}\n message={error?.toString()}\n autoHideDuration={3000}\n onClose={() => resetError?.()}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <Alert\n severity=\"error\"\n sx={{\n width: '100%', display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden',\n }}\n >\n {error?.message}\n </Alert>\n </Snackbar>\n )\n : (() => {\n // setTimeout(() => setError(undefined), 1500)\n return (\n <FlexRow alignSelf=\"stretch\">\n <Alert\n severity=\"error\"\n sx={{ display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden' }}\n >\n {error?.message}\n </Alert>\n </FlexRow>\n )\n })()}\n </>\n )\n}\n","import { useMemo } from 'react'\nimport { useNavigate, useSearchParams } from 'react-router-dom'\n\nimport type { XnsNameCaptureProps } from '../../Props.ts'\nimport { useXnsNameFromLocation } from './useXnsNameFromLocation.ts'\n\nexport const useXnsNameCaptureRouting = (props: XnsNameCaptureProps) => {\n const [params] = useSearchParams()\n const signatureParam = params.get('signature')\n const signatureParamString = signatureParam ? `&signature=${encodeURIComponent(signatureParam)}` : ''\n\n const navigate = useNavigate()\n\n const [name, error] = useXnsNameFromLocation()\n\n return useMemo(() => ({\n ...props,\n defaultXnsName: name,\n routingError: error,\n navigate: props.navigate ?? ((to: string) => navigate(to)),\n paramsString: signatureParamString,\n }), [props, signatureParamString])\n}\n","import { useLocation } from 'react-router-dom'\n\n/**\n * Assumes the user was redirected with a link that contains a username query parameter.\n * @returns The xNS name from the URI username query parameter.\n */\nexport const useXnsNameFromLocation = (): [name: string | undefined, error: Error | undefined] => {\n const location = useLocation()\n const search = new URLSearchParams(location.search)\n const rawName = (search.get('xnsname') ?? search.get('name') ?? search.get('username') ?? '').toLowerCase()\n switch (rawName?.split('.').length) {\n case 1: {\n return [rawName, undefined]\n }\n case 2: {\n const rawNameParts = rawName.split('.')\n if (rawNameParts[1] !== 'xyo') {\n return [, new Error('Invalid xNS name [Bad root]')]\n }\n return [rawNameParts[0], undefined]\n }\n default: {\n return [, new Error('Invalid xNS name [Too many parts]')]\n }\n }\n}\n","import { useMixpanel } from '@xylabs/react-mixpanel'\nimport { useMemo } from 'react'\n\nimport type { XnsNameCaptureProps } from '../Props.ts'\n\nexport const useXnsNameCaptureProviders = (props: XnsNameCaptureProps) => {\n const mixpanel = useMixpanel()\n\n return useMemo(() => ({\n ...props,\n mixpanel: props.mixpanel ?? mixpanel,\n }), [props, mixpanel])\n}\n","import { ArrowForwardRounded } from '@mui/icons-material'\nimport { Stack } from '@mui/material'\nimport type { LinkExProps } from '@xylabs/react-link'\nimport { LinkEx } from '@xylabs/react-link'\nimport { XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport type { Dispatch } from 'react'\nimport React from 'react'\n\nimport type {\n XnsNameCaptureBuyCallbacks, XnsNameCaptureRoutingProps, XnsNameCaptureTrackingProps,\n} from './Props.ts'\n\nexport interface XnsCaptureSecondaryLinkProps extends XnsNameCaptureTrackingProps, XnsNameCaptureRoutingProps, XnsNameCaptureBuyCallbacks, LinkExProps {\n event?: string\n funnel?: string\n placement?: string\n setError?: Dispatch<Error | undefined>\n text?: string\n xnsName: string\n}\n\nexport const XnsCaptureSecondaryLink: React.FC<XnsCaptureSecondaryLinkProps> = ({\n event = 'Click to Reservation',\n funnel = 'xns',\n mixpanel,\n navigate,\n onCaptureName,\n paramsString = '',\n placement = '',\n setError,\n text = 'Or make a free reservation',\n to = '/xns/reservation',\n userEvents,\n xnsName,\n ...props\n}) => {\n return (\n <LinkEx\n paddingX={0}\n color=\"inherit\"\n style={{ textDecoration: 'underline', textUnderlineOffset: '5px' }}\n onClick={async () => {\n mixpanel?.track(event, {\n Funnel: funnel,\n Placement: placement,\n })\n const formattedXnsName = `${xnsName}.xyo`\n const helper = XnsNameHelper.fromString(formattedXnsName)\n const [valid, errors] = await helper.validate()\n if (valid) {\n await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })\n navigate?.(`${to}?username=${xnsName}${paramsString}`)\n await onCaptureName?.(xnsName)\n } else {\n setError?.(new Error(errors.join(', ')))\n }\n }}\n {...props}\n >\n <Stack flexDirection=\"row\" gap={0.5} alignItems=\"center\" sx={{ cursor: 'pointer' }}>\n {text}\n <ArrowForwardRounded />\n </Stack>\n </LinkEx>\n )\n}\n","import { KeyboardArrowRightRounded } from '@mui/icons-material'\nimport type { StandardTextFieldProps } from '@mui/material'\nimport { useMediaQuery, useTheme } from '@mui/material'\nimport { ButtonEx } from '@xylabs/react-button'\nimport { FlexCol, FlexRow } from '@xylabs/react-flexbox'\nimport { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'\nimport type { KeyboardEventHandler } from 'react'\nimport React, { useCallback, useState } from 'react'\n\nimport { XnsEstimateNameTextField } from '../EstimateName/index.ts'\nimport { XnsNameCaptureErrors } from './Errors.tsx'\nimport type { XnsNameCaptureProps } from './Props.ts'\nimport { XnsCaptureSecondaryLink } from './SecondaryLink.js'\n\nexport const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({\n autoFocus = false,\n buttonText = 'Buy My Name',\n children,\n defaultXnsName,\n errorUi = 'alert',\n event = 'Click to Checkout',\n funnel = 'xns',\n mixpanel,\n mobileButtonText = 'Buy',\n navigate,\n onCaptureName: onCaptureNameProp,\n paramsString = '',\n placement = '',\n routingError,\n showSecondary = false,\n to = '/xns/estimation',\n userEvents,\n ...props\n}) => {\n const [xnsName, setXnsName] = useState<string>(() => defaultXnsName ?? '')\n const [error, setError] = useState<Error | undefined>(routingError)\n\n const theme = useTheme()\n const isMobile = useMediaQuery(theme.breakpoints.down('md'))\n\n const captureDisabled = !xnsName || xnsName.length < MIN_DOMAIN_LENGTH\n\n const handleChange: StandardTextFieldProps['onChange'] = (event) => {\n const NsName = XnsNameHelper.mask(event.target.value)\n setXnsName(NsName)\n setError(undefined)\n }\n\n const onCaptureName = useCallback(async () => {\n if (captureDisabled) return\n mixpanel?.track(event, {\n Funnel: funnel,\n Placement: placement,\n })\n const formattedXnsName = `${xnsName}.xyo`\n const helper = XnsNameHelper.fromString(formattedXnsName)\n const [valid, errors] = await helper.validate()\n if (valid) {\n await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })\n await onCaptureNameProp?.(xnsName)\n navigate?.(`${to}?username=${xnsName}${paramsString}`)\n } else {\n setError(new Error(errors.join(', ')))\n }\n }, [event, funnel, mixpanel, paramsString, placement, to, userEvents, xnsName])\n\n const onKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(async (event) => {\n if (event.key === 'Enter' && !captureDisabled) {\n await onCaptureName?.()\n }\n }, [captureDisabled, onCaptureName])\n\n return (\n <FlexCol gap={showSecondary ? 1.5 : 0} alignItems=\"center\" {...props}>\n <FlexRow gap={1}>\n <XnsEstimateNameTextField\n autoFocus={autoFocus}\n label=\"xNS Name\"\n variant=\"outlined\"\n size=\"small\"\n value={xnsName ?? ''}\n onKeyDown={onKeyDown}\n onChange={handleChange}\n onBlur={handleChange}\n />\n <ButtonEx\n disabled={captureDisabled}\n variant=\"contained\"\n color=\"success\"\n endIcon={<KeyboardArrowRightRounded />}\n onClick={onCaptureName}\n >\n {isMobile ? mobileButtonText : buttonText}\n </ButtonEx>\n </FlexRow>\n {(showSecondary === true)\n ? (\n <XnsCaptureSecondaryLink\n xnsName={xnsName}\n placement={placement}\n funnel={funnel}\n setError={setError}\n />\n )\n : null}\n {\n // eslint-disable-next-line unicorn/prefer-logical-operator-over-ternary\n showSecondary ? showSecondary : null\n }\n {children}\n <XnsNameCaptureErrors error={error} errorUi={errorUi} resetError={() => setError(undefined)} />\n </FlexCol>\n )\n}\n","import React, { useMemo } from 'react'\n\nimport { useXnsNameCaptureProviders, useXnsNameCaptureRouting } from './hooks/index.ts'\nimport type { XnsNameCaptureProps } from './Props.ts'\nimport { XnsNameCapture } from './XnsNameCapture.tsx'\n\nexport const XnsNameCaptureWithContext: React.FC<XnsNameCaptureProps> = (props) => {\n const routingProps = useXnsNameCaptureRouting(props)\n const providersProps = useXnsNameCaptureProviders(routingProps)\n\n const updatedProps = useMemo<XnsNameCaptureProps>(() => ({\n ...props,\n ...routingProps,\n ...providersProps,\n }), [providersProps])\n\n return (\n <XnsNameCapture {...updatedProps} />\n )\n}\n"],"mappings":"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","names":["alpha","TextField","useTheme","MIN_DOMAIN_LENGTH","XnsNameHelper","React","useState","XnsEstimateNameTextField","maskOutput","onChange","onChangeProp","onBlur","onBlurProp","props","theme","useTheme","validLength","setValidLength","useState","inputRef","React","useRef","handleChange","event","value","target","XnsNameHelper","mask","current","length","MIN_DOMAIN_LENGTH","handleBlur","maskStartEndHyphens","TextField","inputProps","style","color","palette","text","primary","alpha","Alert","Snackbar","useMediaQuery","useTheme","FlexRow","React","XnsNameCaptureErrors","error","errorUi","resetError","theme","useTheme","isMobile","useMediaQuery","breakpoints","down","React","Snackbar","open","message","toString","autoHideDuration","onClose","anchorOrigin","vertical","horizontal","Alert","severity","sx","width","display","undefined","visibility","FlexRow","alignSelf","useMemo","useNavigate","useSearchParams","useLocation","useXnsNameFromLocation","location","useLocation","search","URLSearchParams","rawName","get","toLowerCase","split","length","undefined","rawNameParts","Error","useXnsNameCaptureRouting","props","params","useSearchParams","signatureParam","get","signatureParamString","encodeURIComponent","navigate","useNavigate","name","error","useXnsNameFromLocation","useMemo","defaultXnsName","routingError","to","paramsString","useMixpanel","useMemo","useXnsNameCaptureProviders","props","mixpanel","useMixpanel","useMemo","ArrowForwardRounded","Stack","LinkEx","XnsNameHelper","React","XnsCaptureSecondaryLink","event","funnel","mixpanel","navigate","onCaptureName","paramsString","placement","setError","text","to","userEvents","xnsName","props","React","LinkEx","paddingX","color","style","textDecoration","textUnderlineOffset","onClick","track","Funnel","Placement","formattedXnsName","helper","XnsNameHelper","fromString","valid","errors","validate","userClick","elementName","elementType","Error","join","Stack","flexDirection","gap","alignItems","sx","cursor","ArrowForwardRounded","KeyboardArrowRightRounded","useMediaQuery","useTheme","ButtonEx","FlexCol","FlexRow","MIN_DOMAIN_LENGTH","XnsNameHelper","React","useCallback","useState","XnsNameCapture","autoFocus","buttonText","children","defaultXnsName","errorUi","event","funnel","mixpanel","mobileButtonText","navigate","onCaptureName","onCaptureNameProp","paramsString","placement","routingError","showSecondary","to","userEvents","props","xnsName","setXnsName","useState","error","setError","theme","useTheme","isMobile","useMediaQuery","breakpoints","down","captureDisabled","length","MIN_DOMAIN_LENGTH","handleChange","NsName","XnsNameHelper","mask","target","value","undefined","useCallback","track","Funnel","Placement","formattedXnsName","helper","fromString","valid","errors","validate","userClick","elementName","elementType","Error","join","onKeyDown","key","React","FlexCol","gap","alignItems","FlexRow","XnsEstimateNameTextField","label","variant","size","onChange","onBlur","ButtonEx","disabled","color","endIcon","KeyboardArrowRightRounded","onClick","XnsCaptureSecondaryLink","XnsNameCaptureErrors","resetError","React","useMemo","XnsNameCaptureWithContext","props","routingProps","useXnsNameCaptureRouting","providersProps","useXnsNameCaptureProviders","updatedProps","useMemo","React","XnsNameCapture"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/react-xns",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.13",
|
|
4
4
|
"description": "Common React library for all XYO projects that use React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xyo",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@types/mixpanel-browser": "^2.50.0",
|
|
60
60
|
"@xylabs/ts-scripts-yarn3": "^4.0.7",
|
|
61
61
|
"@xylabs/tsconfig-react": "^4.0.7",
|
|
62
|
-
"@xyo-network/react-storybook": "^3.0.
|
|
62
|
+
"@xyo-network/react-storybook": "^3.0.13",
|
|
63
63
|
"react": "^18.3.1",
|
|
64
64
|
"react-dom": "^18.3.1",
|
|
65
65
|
"react-router-dom": "^6.26.1",
|
|
@@ -5,7 +5,7 @@ import type { ReactNode } from 'react'
|
|
|
5
5
|
import type { To } from 'react-router-dom'
|
|
6
6
|
|
|
7
7
|
export interface XnsNameCaptureBuyCallbacks {
|
|
8
|
-
|
|
8
|
+
onCaptureName?: (name: string) => Promise<void>
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -24,6 +24,7 @@ export interface XnsNameCaptureTrackingProps {
|
|
|
24
24
|
export interface XnsNameCaptureRoutingProps {
|
|
25
25
|
navigate?: (to: string) => void
|
|
26
26
|
paramsString?: string
|
|
27
|
+
routingError?: Error
|
|
27
28
|
to?: To
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -13,6 +13,6 @@ const Default = Template.bind({})
|
|
|
13
13
|
Default.args = {}
|
|
14
14
|
|
|
15
15
|
const WithOnBuyName = Template.bind({})
|
|
16
|
-
WithOnBuyName.args = { xnsName: 'testing123',
|
|
16
|
+
WithOnBuyName.args = { xnsName: 'testing123', onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
17
17
|
|
|
18
18
|
export { Default, WithOnBuyName }
|
|
@@ -24,7 +24,7 @@ export const XnsCaptureSecondaryLink: React.FC<XnsCaptureSecondaryLinkProps> = (
|
|
|
24
24
|
funnel = 'xns',
|
|
25
25
|
mixpanel,
|
|
26
26
|
navigate,
|
|
27
|
-
|
|
27
|
+
onCaptureName,
|
|
28
28
|
paramsString = '',
|
|
29
29
|
placement = '',
|
|
30
30
|
setError,
|
|
@@ -50,7 +50,7 @@ export const XnsCaptureSecondaryLink: React.FC<XnsCaptureSecondaryLinkProps> = (
|
|
|
50
50
|
if (valid) {
|
|
51
51
|
await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })
|
|
52
52
|
navigate?.(`${to}?username=${xnsName}${paramsString}`)
|
|
53
|
-
await
|
|
53
|
+
await onCaptureName?.(xnsName)
|
|
54
54
|
} else {
|
|
55
55
|
setError?.(new Error(errors.join(', ')))
|
|
56
56
|
}
|
|
@@ -14,6 +14,6 @@ const Default = Template.bind({})
|
|
|
14
14
|
Default.args = {}
|
|
15
15
|
|
|
16
16
|
const WithOnBuyName = Template.bind({})
|
|
17
|
-
WithOnBuyName.args = { navigate: (to: To) => alert(`navigated to: ${to}`),
|
|
17
|
+
WithOnBuyName.args = { navigate: (to: To) => alert(`navigated to: ${to}`), onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
18
18
|
|
|
19
19
|
export { Default, WithOnBuyName }
|
|
@@ -23,21 +23,22 @@ export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
|
23
23
|
mixpanel,
|
|
24
24
|
mobileButtonText = 'Buy',
|
|
25
25
|
navigate,
|
|
26
|
-
|
|
26
|
+
onCaptureName: onCaptureNameProp,
|
|
27
27
|
paramsString = '',
|
|
28
28
|
placement = '',
|
|
29
|
+
routingError,
|
|
29
30
|
showSecondary = false,
|
|
30
31
|
to = '/xns/estimation',
|
|
31
32
|
userEvents,
|
|
32
33
|
...props
|
|
33
34
|
}) => {
|
|
34
35
|
const [xnsName, setXnsName] = useState<string>(() => defaultXnsName ?? '')
|
|
35
|
-
const [error, setError] = useState<Error | undefined>()
|
|
36
|
+
const [error, setError] = useState<Error | undefined>(routingError)
|
|
36
37
|
|
|
37
38
|
const theme = useTheme()
|
|
38
39
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
+
const captureDisabled = !xnsName || xnsName.length < MIN_DOMAIN_LENGTH
|
|
41
42
|
|
|
42
43
|
const handleChange: StandardTextFieldProps['onChange'] = (event) => {
|
|
43
44
|
const NsName = XnsNameHelper.mask(event.target.value)
|
|
@@ -45,9 +46,8 @@ export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
|
45
46
|
setError(undefined)
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
|
|
49
|
+
const onCaptureName = useCallback(async () => {
|
|
50
|
+
if (captureDisabled) return
|
|
51
51
|
mixpanel?.track(event, {
|
|
52
52
|
Funnel: funnel,
|
|
53
53
|
Placement: placement,
|
|
@@ -57,7 +57,7 @@ export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
|
57
57
|
const [valid, errors] = await helper.validate()
|
|
58
58
|
if (valid) {
|
|
59
59
|
await userEvents?.userClick({ elementName: event, elementType: 'xns-cta' })
|
|
60
|
-
await
|
|
60
|
+
await onCaptureNameProp?.(xnsName)
|
|
61
61
|
navigate?.(`${to}?username=${xnsName}${paramsString}`)
|
|
62
62
|
} else {
|
|
63
63
|
setError(new Error(errors.join(', ')))
|
|
@@ -65,10 +65,10 @@ export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
|
65
65
|
}, [event, funnel, mixpanel, paramsString, placement, to, userEvents, xnsName])
|
|
66
66
|
|
|
67
67
|
const onKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(async (event) => {
|
|
68
|
-
if (event.key === 'Enter' && !
|
|
69
|
-
await
|
|
68
|
+
if (event.key === 'Enter' && !captureDisabled) {
|
|
69
|
+
await onCaptureName?.()
|
|
70
70
|
}
|
|
71
|
-
}, [
|
|
71
|
+
}, [captureDisabled, onCaptureName])
|
|
72
72
|
|
|
73
73
|
return (
|
|
74
74
|
<FlexCol gap={showSecondary ? 1.5 : 0} alignItems="center" {...props}>
|
|
@@ -84,11 +84,11 @@ export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
|
84
84
|
onBlur={handleChange}
|
|
85
85
|
/>
|
|
86
86
|
<ButtonEx
|
|
87
|
-
disabled={
|
|
87
|
+
disabled={captureDisabled}
|
|
88
88
|
variant="contained"
|
|
89
89
|
color="success"
|
|
90
90
|
endIcon={<KeyboardArrowRightRounded />}
|
|
91
|
-
onClick={
|
|
91
|
+
onClick={onCaptureName}
|
|
92
92
|
>
|
|
93
93
|
{isMobile ? mobileButtonText : buttonText}
|
|
94
94
|
</ButtonEx>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
Decorator, Meta, StoryFn,
|
|
3
|
+
} from '@storybook/react'
|
|
2
4
|
import React from 'react'
|
|
3
5
|
import type { To } from 'react-router-dom'
|
|
4
6
|
import { BrowserRouter } from 'react-router-dom'
|
|
@@ -7,15 +9,28 @@ import { XnsNameCaptureWithContext } from './XnsNameCaptureWithContext.tsx'
|
|
|
7
9
|
|
|
8
10
|
export default { title: 'modules/xns/XnsNameCaptureWithContext' } as Meta
|
|
9
11
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
+
const testableParams = ['signature', 'username'] as const
|
|
13
|
+
type RouteDecorator = (params: [typeof testableParams[number], string][]) => Decorator
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line react/display-name
|
|
16
|
+
const RouteDecorator: RouteDecorator = params => (Story, args) => {
|
|
17
|
+
// Get the URL object
|
|
12
18
|
const url = new URL(window.location.href)
|
|
13
19
|
|
|
14
|
-
//
|
|
15
|
-
url.searchParams.
|
|
20
|
+
// Remove all stale testable params from the URL
|
|
21
|
+
for (const param of testableParams) url.searchParams.delete(param)
|
|
22
|
+
window.history.replaceState({}, '', url)
|
|
23
|
+
|
|
24
|
+
// Add the new testable params to the URL
|
|
25
|
+
for (const [param, value] of params) url.searchParams.set(param, value)
|
|
16
26
|
|
|
17
|
-
//
|
|
27
|
+
// Replace the URL without reloading
|
|
18
28
|
window.history.replaceState({}, '', url)
|
|
29
|
+
|
|
30
|
+
return <Story {...args} />
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const Template: StoryFn<typeof XnsNameCaptureWithContext> = (args) => {
|
|
19
34
|
return (
|
|
20
35
|
<BrowserRouter>
|
|
21
36
|
<XnsNameCaptureWithContext {...args}></XnsNameCaptureWithContext>
|
|
@@ -24,9 +39,20 @@ const Template: StoryFn<typeof XnsNameCaptureWithContext> = (args) => {
|
|
|
24
39
|
}
|
|
25
40
|
|
|
26
41
|
const Default = Template.bind({})
|
|
42
|
+
Default.decorators = [RouteDecorator([['signature', '0x1234567890abcdef']])]
|
|
27
43
|
Default.args = {}
|
|
28
44
|
|
|
29
|
-
const
|
|
30
|
-
|
|
45
|
+
const WithOnCaptureName = Template.bind({})
|
|
46
|
+
WithOnCaptureName.decorators = [RouteDecorator([['signature', '0x1234567890abcdef']])]
|
|
47
|
+
WithOnCaptureName.args = { navigate: (to: To) => alert(`navigated to: ${to}`), onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
const WithBadXnsNameInRoute = Template.bind({})
|
|
50
|
+
WithBadXnsNameInRoute.decorators = [RouteDecorator([['signature', '0x1234567890abcdef'], ['username', 'badname.xyo.xyo']])]
|
|
51
|
+
WithBadXnsNameInRoute.args = {
|
|
52
|
+
navigate: (to: To) => alert(`navigated to: ${to}`),
|
|
53
|
+
onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
Default, WithBadXnsNameInRoute, WithOnCaptureName,
|
|
58
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
2
|
import { useNavigate, useSearchParams } from 'react-router-dom'
|
|
3
3
|
|
|
4
|
-
import type { XnsNameCaptureProps } from '
|
|
4
|
+
import type { XnsNameCaptureProps } from '../../Props.ts'
|
|
5
|
+
import { useXnsNameFromLocation } from './useXnsNameFromLocation.ts'
|
|
5
6
|
|
|
6
7
|
export const useXnsNameCaptureRouting = (props: XnsNameCaptureProps) => {
|
|
7
8
|
const [params] = useSearchParams()
|
|
@@ -10,8 +11,12 @@ export const useXnsNameCaptureRouting = (props: XnsNameCaptureProps) => {
|
|
|
10
11
|
|
|
11
12
|
const navigate = useNavigate()
|
|
12
13
|
|
|
14
|
+
const [name, error] = useXnsNameFromLocation()
|
|
15
|
+
|
|
13
16
|
return useMemo(() => ({
|
|
14
17
|
...props,
|
|
18
|
+
defaultXnsName: name,
|
|
19
|
+
routingError: error,
|
|
15
20
|
navigate: props.navigate ?? ((to: string) => navigate(to)),
|
|
16
21
|
paramsString: signatureParamString,
|
|
17
22
|
}), [props, signatureParamString])
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useLocation } from 'react-router-dom'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Assumes the user was redirected with a link that contains a username query parameter.
|
|
5
|
+
* @returns The xNS name from the URI username query parameter.
|
|
6
|
+
*/
|
|
7
|
+
export const useXnsNameFromLocation = (): [name: string | undefined, error: Error | undefined] => {
|
|
8
|
+
const location = useLocation()
|
|
9
|
+
const search = new URLSearchParams(location.search)
|
|
10
|
+
const rawName = (search.get('xnsname') ?? search.get('name') ?? search.get('username') ?? '').toLowerCase()
|
|
11
|
+
switch (rawName?.split('.').length) {
|
|
12
|
+
case 1: {
|
|
13
|
+
return [rawName, undefined]
|
|
14
|
+
}
|
|
15
|
+
case 2: {
|
|
16
|
+
const rawNameParts = rawName.split('.')
|
|
17
|
+
if (rawNameParts[1] !== 'xyo') {
|
|
18
|
+
return [, new Error('Invalid xNS name [Bad root]')]
|
|
19
|
+
}
|
|
20
|
+
return [rawNameParts[0], undefined]
|
|
21
|
+
}
|
|
22
|
+
default: {
|
|
23
|
+
return [, new Error('Invalid xNS name [Too many parts]')]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|