Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dashboard] implement feedback modal 9928 #10061

Merged
merged 1 commit into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
score: number;
feedback: string;
laushinka marked this conversation as resolved.
Show resolved Hide resolved
href: string;
path: string;
}
interface TrackDashboardClick {
dnt?: boolean;
path: string;
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 @@ -387,6 +395,10 @@ export default function Menu() {
{
title: "Settings",
link: "/settings",
},
{
title: "Help",
gtsiolis marked this conversation as resolved.
Show resolved Hide resolved
link: "https://www.gitpod.io/support",
separator: true,
},
{
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
111 changes: 111 additions & 0 deletions components/dashboard/src/feedback-form/FeedbackComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* 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 starry from "../images/feedback/starry-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; isModal: boolean }) {
const [text, setText] = useState<string>("");
const [selectedEmoji, setSelectedEmoji] = useState<number | undefined>();

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

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

props.onSubmit();
};

const handleClick = (emojiScore: number) => {
setSelectedEmoji(emojiScore);
};

const emojiGroup = (width: number) => {
laushinka marked this conversation as resolved.
Show resolved Hide resolved
const emojiList = [
{ id: 4, name: "starry", src: starry },
{ id: 3, name: "happy", src: happy },
{ id: 2, name: "meh", src: meh },
{ id: 1, name: "crying", src: crying },
];
return emojiList.map((emoji) => (
<button
className={
"hover:scale-150 transform bg-transparent bottom-5 right-5 cursor-pointer " +
(selectedEmoji === emoji.id ? "" : "grayed")
}
onClick={() => handleClick(emoji.id)}
>
<img src={emoji.src} alt={`${emoji.name} emoji`} width={width || "24px"} title={emoji.name} />
</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 bg-white dark:bg-gray-900">
<div className="relative">
<div className="absolute flex bottom-5 right-5 -space-x-3">{emojiGroup(24)}</div>
laushinka marked this conversation as resolved.
Show resolved Hide resolved
<textarea
gtsiolis marked this conversation as resolved.
Show resolved Hide resolved
laushinka marked this conversation as resolved.
Show resolved Hide resolved
style={{ height: "160px", borderRadius: "6px" }}
autoFocus
className="w-full resize-none text-gray-400 dark:text-gray-400 focus:ring-0 focus:border-gray-400 dark:focus:border-gray-400 rounded-md border dark:bg-gray-800 dark:border-gray-500 border-gray-500"
name="name"
value={text}
placeholder="Have more feedback?"
onChange={(e) => setText(e.target.value)}
/>
</div>
<div>
<p className="text-gray-500">
{" "}
By submitting this form you acknowledge that you have read and understood our{" "}
<a className="gp-link" target="gitpod-privacy" href="https://www.gitpod.io/privacy/">
privacy policy
</a>
.
</p>
</div>
</div>
<div className="flex justify-end mt-6">
<button className="secondary" onClick={props.onClose}>
Cancel
</button>
<button className="ml-2" onClick={onSubmit}>
Send Feedback
gtsiolis marked this conversation as resolved.
Show resolved Hide resolved
</button>
</div>
</>
) : (
<div
className="flex flex-col justify-center -mx-6 px-6 py-4 border-t border-gray-200 dark:border-gray-800"
style={{ height: height }}
>
<p className="text-center text-lg mb-8 text-gray-500 dark:text-gray-400">
We'd love to know what you think!
</p>

<div className="flex items-center justify-center w-full space-x-3">{emojiGroup(50)}</div>
laushinka marked this conversation as resolved.
Show resolved Hide resolved
</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}>
gtsiolis marked this conversation as resolved.
Show resolved Hide resolved
<FeedbackComponent onClose={onClose} onSubmit={onSubmit} isModal={true} />
</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.
6 changes: 6 additions & 0 deletions components/dashboard/src/images/feedback/starry-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/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
.dark .dark\:filter-invert {
@apply filter-invert;
}
.grayed {
filter: grayscale(100%);
}
.grayed:hover {
filter: none;
}
}

@layer components {
Expand Down