Skip to content

Commit cd66efc

Browse files
committed
total overhaul with new inputMode option
1 parent d12e742 commit cd66efc

File tree

13 files changed

+173
-315
lines changed

13 files changed

+173
-315
lines changed

packages/browser-sdk/index.html

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@
1515
const urlParams = new URLSearchParams(window.location.search);
1616
const publishableKey = urlParams.get("publishableKey");
1717
const flagKey = urlParams.get("flagKey") ?? "huddles";
18+
19+
const onFeedbackClick = (e) => {
20+
reflag.requestFeedback({
21+
flagKey,
22+
inputMode: "comment-and-score",
23+
position: { type: "POPOVER", anchor: e.currentTarget },
24+
});
25+
};
1826
</script>
1927
<style>
2028
body {
2129
font-family: sans-serif;
2230
}
2331
#start-huddle {
24-
border: 1px solid black;
25-
padding: 10px;
32+
margin: 100px;
2633
}
2734
</style>
2835
<div id="start-huddle" style="display: none">
29-
<button
30-
onClick="bucket.requestFeedback({flagKey, requireSatisfactionScore: false, position: {type: 'POPOVER', anchor: event.currentTarget}})"
31-
>
32-
Give feedback!
33-
</button>
36+
<button onClick="onFeedbackClick(event)">Give feedback!</button>
3437
<button onClick="reflag.track(flagKey)">Start huddle</button>
3538
</div>
3639

packages/browser-sdk/src/client.ts

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
RequestFeedbackOptions,
88
} from "./feedback/feedback";
99
import * as feedbackLib from "./feedback/ui";
10+
import { OpenFeedbackFormOptions } from "./feedback/ui/types";
1011
import {
1112
CheckEvent,
1213
FallbackFlagOverride,
@@ -24,6 +25,12 @@ import { showToolbarToggle } from "./toolbar";
2425
const isMobile = typeof window !== "undefined" && window.innerWidth < 768;
2526
const isNode = typeof document === "undefined"; // deno supports "window" but not "document" according to https://remix.run/docs/en/main/guides/gotchas
2627

28+
const VALID_INPUT_MODES: Required<OpenFeedbackFormOptions["inputMode"]>[] = [
29+
"comment-and-score",
30+
"comment-only",
31+
"score-only",
32+
];
33+
2734
/**
2835
* (Internal) User context.
2936
*
@@ -701,6 +708,13 @@ export class ReflagClient {
701708
return;
702709
}
703710

711+
if (options.inputMode && !VALID_INPUT_MODES.includes(options.inputMode)) {
712+
this.logger.error(
713+
"`requestFeedback` call ignored. Invalid `inputMode` provided",
714+
);
715+
return;
716+
}
717+
704718
const feedbackData = {
705719
flagKey: options.flagKey,
706720
companyId:
@@ -720,30 +734,22 @@ export class ReflagClient {
720734
position: options.position || this.requestFeedbackOptions.position,
721735
translations:
722736
options.translations || this.requestFeedbackOptions.translations,
723-
openWithCommentVisible: options.openWithCommentVisible,
724-
requireSatisfactionScore: options.requireSatisfactionScore,
737+
inputMode: options.inputMode,
725738
onClose: options.onClose,
726739
onDismiss: options.onDismiss,
727-
onScoreSubmit: async (data) => {
728-
const res = await this.feedback({
729-
...feedbackData,
730-
...data,
731-
});
732-
733-
if (res) {
734-
const json = await res.json();
735-
return { feedbackId: json.feedbackId };
736-
}
737-
return { feedbackId: undefined };
738-
},
739740
onSubmit: async (data) => {
740741
// Default onSubmit handler
741-
await this.feedback({
742+
const res = await this.feedback({
742743
...feedbackData,
743744
...data,
744745
});
745746

746-
options.onAfterSubmit?.(data);
747+
if (!res) return;
748+
749+
const json = res ? await res.json() : {};
750+
options.onAfterSubmit?.({ ...data, ...json });
751+
752+
return json;
747753
},
748754
});
749755
}, 1);

packages/browser-sdk/src/feedback/feedback.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export class AutoFeedback {
378378
message: FeedbackPrompt,
379379
completionHandler: FeedbackPromptCompletionHandler,
380380
) {
381-
let feedbackId: string | undefined = undefined;
381+
const feedbackId: string | undefined = undefined;
382382

383383
await this.feedbackPromptEvent({
384384
promptId: message.promptId,
@@ -435,24 +435,16 @@ export class AutoFeedback {
435435
feedbackLib.openFeedbackForm({
436436
key: message.featureId,
437437
title: message.question,
438-
onScoreSubmit: async (data) => {
439-
const res = await replyCallback(data);
440-
feedbackId = res.feedbackId;
441-
return { feedbackId: res.feedbackId };
442-
},
443438
onSubmit: async (data) => {
444-
await replyCallback(data);
445-
options.onAfterSubmit?.(data);
439+
const res = await replyCallback(data);
440+
if (!res) return;
441+
options.onAfterSubmit?.({ ...data, ...res });
442+
return res;
446443
},
447444
onDismiss: () => replyCallback(null),
448445
position: this.position,
449446
translations: this.feedbackTranslations,
450447
...options,
451-
openWithCommentVisible:
452-
options.requireSatisfactionScore === false
453-
? true
454-
: options.openWithCommentVisible,
455-
requireSatisfactionScore: options.requireSatisfactionScore,
456448
});
457449
},
458450
};

packages/browser-sdk/src/feedback/ui/Button.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
user-select: none;
77
position: relative;
88
white-space: nowrap;
9-
height: 2rem;
9+
height: 1.85rem;
1010
padding-inline-start: 0.75rem;
1111
padding-inline-end: 0.75rem;
1212
gap: 0.5em;
@@ -27,11 +27,11 @@
2727
&.primary {
2828
background-color: var(
2929
--reflag-feedback-dialog-primary-button-background-color,
30-
white
30+
#09090b
3131
);
32-
color: var(--reflag-feedback-dialog-primary-button-color, #1e1f24);
32+
color: var(--reflag-feedback-dialog-primary-button-color, white);
3333
border: 1px solid
34-
var(--reflag-feedback-dialog-primary-border-color, #d8d9df);
34+
var(--reflag-feedback-dialog-primary-border-color, #09090b);
3535
}
3636

3737
&:disabled {

packages/browser-sdk/src/feedback/ui/FeedbackDialog.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.dialog {
22
position: fixed;
33
width: 210px;
4-
padding: 16px 22px 10px;
4+
padding: 16px 16px 16px;
55
font-size: var(--reflag-feedback-dialog-font-size, 1rem);
66
font-family: var(
77
--reflag-feedback-dialog-font-family,

packages/browser-sdk/src/feedback/ui/FeedbackDialog.tsx

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { FeedbackForm } from "./FeedbackForm";
1111
import styles from "./index.css?inline";
1212
import { RadialProgress } from "./RadialProgress";
1313
import {
14-
FeedbackScoreSubmission,
1514
FeedbackSubmission,
1615
OpenFeedbackFormOptions,
1716
WithRequired,
@@ -25,26 +24,19 @@ export type FeedbackDialogProps = WithRequired<
2524
const INACTIVE_DURATION_MS = 20 * 1000;
2625
const SUCCESS_DURATION_MS = 3 * 1000;
2726

27+
export type FormState = "idle" | "submitting" | "submitted" | "error";
28+
2829
export const FeedbackDialog: FunctionComponent<FeedbackDialogProps> = ({
2930
key,
3031
title = DEFAULT_TRANSLATIONS.DefaultQuestionLabel,
3132
position,
3233
translations = DEFAULT_TRANSLATIONS,
33-
openWithCommentVisible = false,
34-
requireSatisfactionScore = true,
34+
inputMode = "comment-and-score",
3535
onClose,
3636
onDismiss,
3737
onSubmit,
38-
onScoreSubmit,
3938
}) => {
40-
// If requireSatisfactionScore is false, always show comment field
41-
const effectiveOpenWithCommentVisible =
42-
requireSatisfactionScore === false ? true : openWithCommentVisible;
43-
44-
const [feedbackId, setFeedbackId] = useState<string | undefined>(undefined);
45-
const [scoreState, setScoreState] = useState<
46-
"idle" | "submitting" | "submitted"
47-
>("idle");
39+
const [formState, setFormState] = useState<FormState>("idle");
4840

4941
const { isOpen, close } = useDialog({ onClose, initialValue: true });
5042

@@ -56,24 +48,21 @@ export const FeedbackDialog: FunctionComponent<FeedbackDialogProps> = ({
5648

5749
const submit = useCallback(
5850
async (data: Omit<FeedbackSubmission, "feedbackId">) => {
59-
await onSubmit({ ...data, feedbackId });
60-
autoClose.startWithDuration(SUCCESS_DURATION_MS);
61-
},
62-
[autoClose, feedbackId, onSubmit],
63-
);
64-
65-
const submitScore = useCallback(
66-
async (data: Omit<FeedbackScoreSubmission, "feedbackId">) => {
67-
if (onScoreSubmit !== undefined) {
68-
setScoreState("submitting");
69-
70-
const res = await onScoreSubmit({ ...data, feedbackId });
71-
setFeedbackId(res.feedbackId);
72-
setScoreState("submitted");
51+
try {
52+
setFormState("submitting");
53+
const res = await onSubmit({ ...data });
54+
if (!res) throw new Error("Failed to submit feedback");
55+
setFormState("submitted");
56+
autoClose.startWithDuration(SUCCESS_DURATION_MS);
57+
} catch (error) {
58+
setFormState("error");
59+
console.error("Couldn't submit feedback with Reflag:", error);
60+
throw error;
7361
}
7462
},
75-
[feedbackId, onScoreSubmit],
63+
[autoClose, onSubmit],
7664
);
65+
7766
const dismiss = useCallback(() => {
7867
autoClose.stop();
7968
close();
@@ -94,14 +83,12 @@ export const FeedbackDialog: FunctionComponent<FeedbackDialogProps> = ({
9483
<>
9584
<FeedbackForm
9685
key={key}
97-
openWithCommentVisible={effectiveOpenWithCommentVisible}
86+
inputMode={inputMode}
9887
question={title}
99-
requireSatisfactionScore={requireSatisfactionScore}
100-
scoreState={scoreState}
10188
t={{ ...DEFAULT_TRANSLATIONS, ...translations }}
10289
onInteraction={autoClose.stop}
103-
onScoreSubmit={submitScore}
10490
onSubmit={submit}
91+
formState={formState}
10592
/>
10693

10794
<button class="close" onClick={dismiss}>
@@ -111,7 +98,7 @@ export const FeedbackDialog: FunctionComponent<FeedbackDialogProps> = ({
11198
progress={1.0 - autoClose.elapsedFraction}
11299
/>
113100
)}
114-
<Close />
101+
<Close width={18} height={18} />
115102
</button>
116103
</>
117104
</Dialog>

packages/browser-sdk/src/feedback/ui/FeedbackForm.css

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.container {
22
overflow-y: hidden;
33
transition: max-height 400ms cubic-bezier(0.65, 0, 0.35, 1);
4+
max-height: 999px;
45
}
56

67
.form {
@@ -33,21 +34,16 @@
3334
align-items: flex-start;
3435
gap: 10px;
3536
transition: opacity 400ms cubic-bezier(0.65, 0, 0.35, 1);
36-
37-
opacity: 0;
38-
position: absolute;
39-
top: 0;
40-
left: 0;
4137
}
4238

4339
.title {
4440
color: var(--reflag-feedback-dialog-color, #1e1f24);
45-
font-size: 15px;
41+
font-size: 14px;
4642
font-weight: 400;
4743
line-height: 115%;
4844
text-wrap: balance;
4945
max-width: calc(100% - 20px);
50-
margin-bottom: 6px;
46+
margin-bottom: 0px;
5147
line-height: 1.3;
5248
}
5349

@@ -111,8 +107,7 @@
111107
.error {
112108
margin: 0;
113109
color: var(--reflag-feedback-dialog-error-color, #e53e3e);
114-
font-size: 0.8125em;
115-
font-weight: 500;
110+
font-size: 13px;
116111
}
117112

118113
.submitted {

0 commit comments

Comments
 (0)