Skip to content

Commit ab9830a

Browse files
author
Laurie T. Malau
committed
Feedback modal
1 parent 1646db7 commit ab9830a

File tree

9 files changed

+108
-38
lines changed

9 files changed

+108
-38
lines changed

components/dashboard/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { parseProps } from "./start/StartWorkspace";
4848
import SelectIDEModal from "./settings/SelectIDEModal";
4949
import { StartPage, StartPhase } from "./start/StartPage";
5050
import { isGitpodIo } from "./utils";
51+
import FeedbackFormModal from "./feedback-form/FeedbackModal";
5152

5253
const Setup = React.lazy(() => import(/* webpackPrefetch: true */ "./Setup"));
5354
const Workspaces = React.lazy(() => import(/* webpackPrefetch: true */ "./workspaces/Workspaces"));
@@ -372,6 +373,7 @@ function App() {
372373
<AdminRoute path="/admin/license" component={License} />
373374
<AdminRoute path="/admin/settings" component={AdminSettings} />
374375

376+
<Route path="/feedback" exact component={FeedbackFormModal} />
375377
<Route path={["/", "/login"]} exact>
376378
<Redirect to={workspacesPathMain} />
377379
</Route>

components/dashboard/src/Login.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* See License-AGPL.txt in the project root for license information.
55
*/
66

7+
//@ts-nocheck
78
import { AuthProviderInfo } from "@gitpod/gitpod-protocol";
89
import * as GitpodCookie from "@gitpod/gitpod-protocol/lib/util/gitpod-cookie";
910
import { useContext, useEffect, useState } from "react";
@@ -22,6 +23,7 @@ import fresh from "./images/welcome/fresh.svg";
2223
import prebuild from "./images/welcome/prebuild.svg";
2324
import exclamation from "./images/exclamation.svg";
2425
import { getURLHash } from "./App";
26+
import ErrorMessage from "./components/ErrorMessage";
2527

2628
function Item(props: { icon: string; iconSize?: string; text: string }) {
2729
const iconSize = props.iconSize || 28;
@@ -225,19 +227,10 @@ export function Login() {
225227
))
226228
)}
227229
</div>
228-
229-
{errorMessage && (
230-
<div className="mt-16 flex space-x-2 py-6 px-6 w-96 justify-between bg-gitpod-kumquat-light rounded-xl">
231-
<div className="pr-3 self-center w-6">
232-
<img src={exclamation} />
233-
</div>
234-
<div className="flex-1 flex flex-col">
235-
<p className="text-gitpod-red text-sm">{errorMessage}</p>
236-
</div>
237-
</div>
238-
)}
230+
{errorMessage && <ErrorMessage imgSrc={exclamation} message={errorMessage} />}
239231
</div>
240232
</div>
233+
241234
<div className="flex-none mx-auto h-20 text-center">
242235
<span className="text-gray-400">
243236
By signing in, you agree to our{" "}

components/dashboard/src/Menu.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ export default function Menu() {
401401
link: "https://www.gitpod.io/support",
402402
separator: true,
403403
},
404+
{
405+
title: "Help",
406+
link: "https://www.gitpod.io/support",
407+
},
404408
{
405409
title: "Logout",
406410
href: gitpodHostUrl.asApiLogout().toString(),
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import FeedbackComponent from "../feedback-form/FeedbackComponent";
8+
9+
function ErrorMessage(props: { imgSrc: string; imgAlt?: string; message: string }) {
10+
return (
11+
<>
12+
<div className="mt-16 flex space-x-2 py-6 px-6 w-96 justify-between bg-gitpod-kumquat-light rounded-xl">
13+
<div className="pr-3 self-center w-6">
14+
<img src={props.imgSrc} alt={props.imgAlt || "An error message"} />
15+
</div>
16+
<div className="flex-1 flex flex-col">
17+
<p className="text-gitpod-red text-sm">{props.message}</p>
18+
</div>
19+
</div>
20+
<FeedbackComponent
21+
message={"Was this error message helpful?"}
22+
initialSize={24}
23+
isError={true}
24+
isModal={false}
25+
/>
26+
</>
27+
);
28+
}
29+
30+
export default ErrorMessage;

components/dashboard/src/feedback-form/FeedbackComponent.tsx

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,26 @@ import meh from "../images/feedback/meh-emoji.svg";
1111
import crying from "../images/feedback/crying-emoji.svg";
1212
import { trackEvent } from "../Analytics";
1313

14-
function FeedbackComponent(props: { onClose: () => void; onSubmit: () => void; isModal: boolean }) {
14+
function FeedbackComponent(props: {
15+
onClose?: () => void;
16+
onSubmit?: () => void;
17+
isModal: boolean;
18+
isError: boolean;
19+
message?: string;
20+
initialSize?: number;
21+
}) {
1522
const [text, setText] = useState<string>("");
1623
const [selectedEmoji, setSelectedEmoji] = useState<number | undefined>();
24+
const [isFeedbackSubmitted, setIsFeedbackSubmitted] = useState<boolean>(false);
1725

1826
const height = props.isModal ? "300px" : "";
1927

28+
const onClose = () => {
29+
if (props.onClose) {
30+
props.onClose();
31+
}
32+
setSelectedEmoji(undefined);
33+
};
2034
const onSubmit = () => {
2135
if (selectedEmoji) {
2236
const feedbackObj = {
@@ -28,7 +42,11 @@ function FeedbackComponent(props: { onClose: () => void; onSubmit: () => void; i
2842
trackEvent("feedback_submitted", feedbackObj);
2943
}
3044

31-
props.onSubmit();
45+
if (props.onSubmit) {
46+
props?.onSubmit();
47+
}
48+
49+
setIsFeedbackSubmitted(true);
3250
};
3351

3452
const handleClick = (emojiScore: number) => {
@@ -56,10 +74,25 @@ function FeedbackComponent(props: { onClose: () => void; onSubmit: () => void; i
5674
};
5775
return (
5876
<>
59-
<h3 className="mb-4">Send Feedback</h3>
60-
{selectedEmoji ? (
77+
{props.isModal && <h3 className="mb-4">Send Feedback</h3>}
78+
{props.isModal && !selectedEmoji && (
79+
<div
80+
className="flex flex-col justify-center -mx-6 px-6 py-4 border-t border-gray-200 dark:border-gray-800"
81+
style={{ height: height }}
82+
>
83+
<p className="text-center text-lg mb-8 text-gray-500 dark:text-gray-400">
84+
We'd love to know what you think!
85+
</p>
86+
</div>
87+
)}
88+
{selectedEmoji && !isFeedbackSubmitted && (
6189
<>
62-
<div className="flex flex-col -mx-6 px-6 py-4 border-t border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900">
90+
<div
91+
className={
92+
"flex flex-col -mx-6 px-6 py-4 border-t border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 " +
93+
(props.isError ? "w-6/12 mt-6" : "")
94+
}
95+
>
6396
<div className="relative">
6497
<div className="absolute flex bottom-5 right-5 -space-x-3">{emojiGroup(24)}</div>
6598
<textarea
@@ -83,25 +116,26 @@ function FeedbackComponent(props: { onClose: () => void; onSubmit: () => void; i
83116
</p>
84117
</div>
85118
</div>
86-
<div className="flex justify-end mt-6">
87-
<button className="secondary" onClick={props.onClose}>
119+
<div className={"flex justify-end mt-6 " + (props.isError ? "mb-6" : "")}>
120+
<button className="secondary" onClick={onClose}>
88121
Cancel
89122
</button>
90123
<button className="ml-2" onClick={onSubmit}>
91124
Send Feedback
92125
</button>
93126
</div>
94127
</>
95-
) : (
96-
<div
97-
className="flex flex-col justify-center -mx-6 px-6 py-4 border-t border-gray-200 dark:border-gray-800"
98-
style={{ height: height }}
99-
>
100-
<p className="text-center text-lg mb-8 text-gray-500 dark:text-gray-400">
101-
We'd love to know what you think!
102-
</p>
128+
)}
129+
{!isFeedbackSubmitted && !selectedEmoji && !props.isModal && (
130+
<div className="flex flex-col -mx-6 px-6 py-4 border-gray-200 dark:border-gray-800">
131+
<h4 className="text-center text-xl">{props.message}</h4>
103132

104-
<div className="flex items-center justify-center w-full space-x-3">{emojiGroup(50)}</div>
133+
<div className="flex items-center justify-center w-full">{emojiGroup(props.initialSize || 50)}</div>
134+
</div>
135+
)}
136+
{isFeedbackSubmitted && (
137+
<div className="flex flex-col -mx-6 px-6 py-4 border-gray-200 dark:border-gray-800">
138+
<h4 className="text-center text-xl">Thanks for your feedback, we appreciate it.</h4>
105139
</div>
106140
)}
107141
</>

components/dashboard/src/feedback-form/FeedbackModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function FeedbackFormModal(props: { onClose: () => void }) {
1818

1919
return (
2020
<Modal visible={true} onClose={onClose}>
21-
<FeedbackComponent onClose={onClose} onSubmit={onSubmit} isModal={true} />
21+
<FeedbackComponent onClose={onClose} onSubmit={onSubmit} isModal={true} isError={false} />
2222
</Modal>
2323
);
2424
}
Lines changed: 6 additions & 0 deletions
Loading

components/dashboard/src/projects/NewProject.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import moment from "moment";
1919
import { UserContext } from "../user-context";
2020
import { trackEvent } from "../Analytics";
2121
import exclamation from "../images/exclamation.svg";
22+
import ErrorMessage from "../components/ErrorMessage";
2223

2324
export default function NewProject() {
2425
const location = useLocation();
@@ -744,16 +745,7 @@ function GitProviders(props: {
744745
})}
745746
</div>
746747

747-
{errorMessage && (
748-
<div className="mt-16 flex space-x-2 py-6 px-6 w-96 justify-between bg-gitpod-kumquat-light rounded-xl">
749-
<div className="pr-3 self-center w-6">
750-
<img src={exclamation} />
751-
</div>
752-
<div className="flex-1 flex flex-col">
753-
<p className="text-gitpod-red text-sm">{errorMessage}</p>
754-
</div>
755-
</div>
756-
)}
748+
{errorMessage && <ErrorMessage imgSrc={exclamation} message={errorMessage} />}
757749
</div>
758750
</div>
759751
);

components/dashboard/src/start/CreateWorkspace.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { SelectAccountPayload } from "@gitpod/gitpod-protocol/lib/auth";
2323
import { SelectAccountModal } from "../settings/SelectAccountModal";
2424
import { watchHeadlessLogs } from "../components/PrebuildLogs";
2525
import CodeText from "../components/CodeText";
26+
import FeedbackComponent from "../feedback-form/FeedbackComponent";
2627

2728
const WorkspaceLogs = React.lazy(() => import("../components/WorkspaceLogs"));
2829

@@ -432,6 +433,14 @@ function RepositoryNotFoundView(p: { error: StartWorkspaceError }) {
432433
<CodeText>{repoFullName}</CodeText>
433434
</p>
434435
{statusMessage}
436+
{p.error && (
437+
<FeedbackComponent
438+
isModal={false}
439+
message={"Was this error message helpful?"}
440+
isError={true}
441+
initialSize={24}
442+
/>
443+
)}
435444
</StartPage>
436445
);
437446
}

0 commit comments

Comments
 (0)