Skip to content

Commit

Permalink
Feedback modal
Browse files Browse the repository at this point in the history
  • Loading branch information
laushinka committed May 18, 2022
1 parent 845d718 commit 38367cd
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 7 deletions.
10 changes: 8 additions & 2 deletions components/dashboard/src/Analytics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import Cookies from "js-cookie";
import { v4 } from "uuid";
import { Experiment } from "./experiments";

export type Event = "invite_url_requested" | "organisation_authorised" | "dotfile_repo_changed";
export type Event = "invite_url_requested" | "organisation_authorised" | "dotfile_repo_changed" | "feedback_submitted";
type InternalEvent = Event | "path_changed" | "dashboard_clicked";

export type EventProperties = TrackOrgAuthorised | TrackInviteUrlRequested | TrackDotfileRepo;
export type EventProperties = TrackOrgAuthorised | TrackInviteUrlRequested | TrackDotfileRepo | TrackFeedback;
type InternalEventProperties = TrackUIExperiments & (EventProperties | TrackDashboardClick | TrackPathChanged);

export interface TrackOrgAuthorised {
Expand All @@ -30,6 +30,12 @@ export interface TrackDotfileRepo {
current: string;
}

export interface TrackFeedback {
selectedEmoji: number;
text: string;
href: string;
path: string;
}
interface TrackDashboardClick {
dnt?: boolean;
path: string;
Expand Down
2 changes: 2 additions & 0 deletions components/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { parseProps } from "./start/StartWorkspace";
import SelectIDEModal from "./settings/SelectIDEModal";
import { StartPage, StartPhase } from "./start/StartPage";
import { isGitpodIo } from "./utils";
import FeedbackFormModal from "./feedback-form/FeedbackModal";

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

<Route path="/feedback" exact component={FeedbackFormModal} />
<Route path={["/", "/login"]} exact>
<Redirect to={workspacesPathMain} />
</Route>
Expand Down
21 changes: 17 additions & 4 deletions components/dashboard/src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { getTeamSettingsMenu } from "./teams/TeamSettings";
import { getProjectSettingsMenu } from "./projects/ProjectSettings";
import { ProjectContext } from "./projects/project-context";
import { PaymentContext } from "./payment-context";
import FeedbackFormModal from "./feedback-form/FeedbackModal";

interface Entry {
title: string;
Expand All @@ -41,6 +42,7 @@ export default function Menu() {
const { showPaymentUI, setShowPaymentUI, setCurrency, setIsStudent, setIsChargebeeCustomer } =
useContext(PaymentContext);
const { project, setProject } = useContext(ProjectContext);
const [isFeedbackFormVisible, setFeedbackFormVisible] = useState<boolean>(false);

const match = useRouteMatch<{ segment1?: string; segment2?: string; segment3?: string }>(
"/(t/)?:segment1/:segment2?/:segment3?",
Expand Down Expand Up @@ -227,12 +229,15 @@ export default function Menu() {
title: "Docs",
link: "https://www.gitpod.io/docs/",
},
{
title: "Help",
link: "https://www.gitpod.io/support",
},
];

const handleFeedbackFormClick = () => {
setFeedbackFormVisible(true);
};

const onFeedbackFormClose = () => {
setFeedbackFormVisible(false);
};
const renderTeamMenu = () => {
return (
<div className="flex p-1 pl-3 ">
Expand Down Expand Up @@ -371,6 +376,9 @@ export default function Menu() {
/>
</li>
))}
<li className="cursor-pointer">
<PillMenuItem name="Feedback" onClick={handleFeedbackFormClick} />
</li>
</ul>
</nav>
<div
Expand All @@ -389,6 +397,10 @@ export default function Menu() {
link: "/settings",
separator: true,
},
{
title: "Help",
link: "https://www.gitpod.io/support",
},
{
title: "Logout",
href: gitpodHostUrl.asApiLogout().toString(),
Expand All @@ -403,6 +415,7 @@ export default function Menu() {
</ContextMenu>
</div>
</div>
{isFeedbackFormVisible && <FeedbackFormModal onClose={onFeedbackFormClose} />}
</div>
{!isMinimalUI && !prebuildId && (
<nav className="flex">
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/components/PillMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Link } from "react-router-dom";

export default function PillMenuItem(p: {
name: string;
selected: boolean;
selected?: boolean;
link?: string;
onClick?: (event: React.MouseEvent) => void;
}) {
Expand Down
178 changes: 178 additions & 0 deletions components/dashboard/src/feedback-form/FeedbackComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/

import { useState } from "react";
import starryEyed from "../images/feedback/starry-eyed-emoji.svg";
import happy from "../images/feedback/happy-emoji.svg";
import meh from "../images/feedback/meh-emoji.svg";
import crying from "../images/feedback/crying-emoji.svg";
import { trackEvent } from "../Analytics";

function FeedbackComponent(props: { onClose: () => void; onSubmit: () => void }) {
const [text, setText] = useState<string>("");
const [selectedEmoji, setSelectedEmoji] = useState<number | undefined>();

const emojiScore: any = {
starry: 4,
happy: 3,
meh: 2,
crying: 1,
};

const onSubmit = () => {
if (selectedEmoji) {
const feedbackObj = {
selectedEmoji,
text,
href: window.location.href,
path: window.location.pathname,
};
trackEvent("feedback_submitted", feedbackObj);
}

props.onSubmit();
};

const handleClick = (target: any) => {
const title = target.title;
setSelectedEmoji(emojiScore[title]);
};

const emojiGroup = (width: number) => {
return (
<>
<button
className={
"hover:scale-150 transform bg-transparent bottom-5 right-5 cursor-pointer " +
(selectedEmoji === emojiScore["starry"] ? "" : "grayed")
}
onClick={(e) => handleClick(e.target)}
>
<img src={starryEyed} alt="starry eyed emoji" width={width || "24px"} title="starry" />
</button>
<button
className={
"hover:scale-150 transform bg-transparent bottom-5 right-5 cursor-pointer " +
(selectedEmoji === emojiScore["happy"] ? "" : "grayed")
}
onClick={(e) => handleClick(e.target)}
>
<img
className="bottom-5 right-5 cursor-pointer"
title="happy"
src={happy}
alt="happy emoji"
width={width}
/>
</button>
<button
className={
"hover:scale-150 transform bg-transparent bottom-5 right-5 cursor-pointer " +
(selectedEmoji === emojiScore["meh"] ? "" : "grayed")
}
onClick={(e) => handleClick(e.target)}
>
<img
className="bottom-5 right-5 cursor-pointer"
title="meh"
src={meh}
alt="meh emoji"
width={width}
/>
</button>
<button
className={
"hover:scale-150 transform bg-transparent bottom-5 right-5 cursor-pointer " +
(selectedEmoji === emojiScore["crying"] ? "" : "grayed")
}
onClick={(e) => handleClick(e.target)}
>
<img
className="bottom-5 right-5 cursor-pointer"
title="crying"
src={crying}
alt="crying emoji"
width={width}
/>
</button>
</>
);
};
return (
<>
<h3 className="mb-4">Send Feedback</h3>
{selectedEmoji ? (
<div className="flex flex-col -mx-6 px-6 py-4 border-t border-b border-gray-200 dark:border-gray-800">
<div className="relative">
<div className="absolute flex bottom-5 right-5 gap-3">{emojiGroup(24)}</div>
<textarea
style={{ height: "160px", borderRadius: "6px" }}
autoFocus
className="w-full"
name="name"
value={text}
placeholder="Your feedback..."
onChange={(e) => setText(e.target.value)}
/>
</div>
<div>
<p className="pt-4">
Alternatively, consider opening{" "}
<a
className="gp-link"
href="https://github.com/gitpod-io/gitpod/issues/new?assignees=&labels=type%3A+bug&template=bug_report.yml"
target="_blank"
rel="noreferrer"
>
{" "}
a bug report{" "}
</a>
or
<a
className="gp-link"
href="https://github.com/gitpod-io/gitpod/issues/new?assignees=&labels=&template=feature_request.md&title="
target="_blank"
rel="noreferrer"
>
{" "}
a feature request{" "}
</a>{" "}
in our issue tracker.
</p>
<p className="pt-4">
{" "}
By submitting this form I acknowledge that I have read and understood Gitpod’s{" "}
<a
className="gp-link hover:text-gray-600"
target="gitpod-privacy"
href="https://www.gitpod.io/privacy/"
>
privacy policy
</a>
.
</p>
</div>
<div className="flex justify-end mt-6">
<button className="secondary" onClick={props.onClose}>
Cancel
</button>
<button className="ml-2" onClick={onSubmit}>
Send Feedback
</button>
</div>
</div>
) : (
<div className="flex flex-col -mx-6 px-6 py-4 border-t border-gray-200 dark:border-gray-800">
<h4 className="text-center text-xl mb-4">We'd love to know what you think!</h4>

<div className="flex items-center justify-center w-full space-x-3">{emojiGroup(50)}</div>
</div>
)}
</>
);
}

export default FeedbackComponent;
26 changes: 26 additions & 0 deletions components/dashboard/src/feedback-form/FeedbackModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/

import Modal from "../components/Modal";
import FeedbackComponent from "./FeedbackComponent";

function FeedbackFormModal(props: { onClose: () => void }) {
const onClose = () => {
props.onClose();
};

const onSubmit = () => {
props.onClose();
};

return (
<Modal visible={true} onClose={onClose}>
<FeedbackComponent onClose={onClose} onSubmit={onSubmit} />
</Modal>
);
}

export default FeedbackFormModal;
10 changes: 10 additions & 0 deletions components/dashboard/src/images/feedback/crying-emoji.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions components/dashboard/src/images/feedback/happy-emoji.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions components/dashboard/src/images/feedback/meh-emoji.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 38367cd

Please sign in to comment.