diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.css b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.css
index 73bc12b65..602ebf0bc 100644
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.css
+++ b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.css
@@ -1,5 +1,9 @@
@layer nimbus-layout {
- .report-package--centered {
+ .report-package__body {
+ min-width: 600px;
+ }
+
+ .report-package__body--centered {
align-items: center;
justify-content: center;
text-align: center;
@@ -42,4 +46,10 @@
font-size: var(--font-size-body-md);
line-height: var(--line-height-md);
}
+
+ @media (width <= 650px) {
+ .report-package__body {
+ min-width: 95vw;
+ }
+ }
}
diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageForm.tsx b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.tsx
similarity index 51%
rename from apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageForm.tsx
rename to apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.tsx
index 7b20fb251..5d46f58b0 100644
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageForm.tsx
+++ b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackage.tsx
@@ -1,11 +1,14 @@
+import "./ReportPackage.css";
import { useReducer, useState } from "react";
import {
Modal,
NewAlert,
NewButton,
+ NewIcon,
NewSelect,
NewTextInput,
+ useToast,
type SelectOption,
} from "@thunderstore/cyberstorm";
import {
@@ -13,8 +16,32 @@ import {
type PackageListingReportRequestData,
packageListingReport,
} from "@thunderstore/thunderstore-api";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm";
+import {
+ faFaceSaluting,
+ faFlagSwallowtail,
+} from "@fortawesome/pro-solid-svg-icons";
+
+export function ReportPackageButton(
+ props: React.HTMLAttributes
+) {
+ return (
+
+
+
+
+
+ );
+}
+
+ReportPackageButton.displayName = "ReportPackageButton";
const reportOptions: SelectOption[] =
[
@@ -27,29 +54,20 @@ const reportOptions: SelectOption[] =
{ value: "Other", label: "Other" },
];
-export interface ReportPackageFormProps {
+export interface ReportPackageProps {
community: string;
namespace: string;
package: string;
config: () => RequestConfig;
}
-interface ReportPackageFormFullProps extends ReportPackageFormProps {
- error: string | null;
- onOpenChange: (isOpen: boolean) => void;
- setError: (error: string | null) => void;
- setIsSubmitted: (isSubmitted: boolean) => void;
-}
+export function ReportPackage(props: ReportPackageProps) {
+ const { config, ...requestParams } = props;
+
+ const [submitted, setSubmitted] = useState(false);
+ const [modalOpen, setModalOpen] = useState(false);
-export function ReportPackageForm(props: ReportPackageFormFullProps) {
- const {
- config,
- onOpenChange,
- setIsSubmitted,
- error,
- setError,
- ...requestParams
- } = props;
+ const toast = useToast();
function formFieldUpdateAction(
state: PackageListingReportRequestData,
@@ -95,21 +113,24 @@ export function ReportPackageForm(props: ReportPackageFormFullProps) {
inputs: formInputs,
submitor,
onSubmitSuccess: () => {
- setIsSubmitted(true);
- setError(null);
+ setSubmitted(true);
},
onSubmitError: (error) => {
let message = `Error occurred: ${error.message || "Unknown error"}`;
if (error.message === "401: Unauthorized") {
message = "You must be logged in to report a package.";
}
- setError(message);
+ toast.addToast({
+ csVariant: "danger",
+ children: message,
+ duration: 8000,
+ });
},
});
- return (
+ const form = (
<>
-
+
- {error && (
+ {strongForm.inputErrors ||
+ strongForm.refineError ||
+ strongForm.submitError ? (
-
{error}
+ {strongForm.inputErrors ? (
+
+ {Object.entries(strongForm.inputErrors).map(([key, value]) => (
+
+ {key}:{" "}
+ {Array.isArray(value) ? value.join(", ") : value}
+
+ ))}
+
+ ) : null}
+ {strongForm.refineError ? (
+
+ Error while refining: {strongForm.refineError.message}
+
+ ) : null}
+ {strongForm.submitError ? (
+
+ Error while submitting: {strongForm.submitError.message}
+
+ ) : null}
- )}
+ ) : null}
- onOpenChange(false)}>
- Cancel
-
+
+ Cancel
+
Send report
>
);
+
+ const done = (
+ <>
+
+
+
+
+
+
+ Thank you for your report
+
+ We've received your report and will review the content shortly.
+
+ Your feedback helps keep our community safe.
+
+
+
+
+ Close
+
+
+ >
+ );
+
+ return (
+ {
+ if (modalOpen && submitted && !isOpen) {
+ // If the modal is being closed after a successful submission,
+ // reset the form state.
+ updateFormFieldState({ field: "reason", value: "Other" });
+ updateFormFieldState({ field: "description", value: "" });
+ setSubmitted(false);
+ }
+ setModalOpen(isOpen);
+ }}
+ trigger={}
+ >
+ {submitted ? done : form}
+
+ );
}
-ReportPackageForm.displayName = "ReportPackageForm";
+ReportPackage.displayName = "ReportPackage";
diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageButton.tsx b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageButton.tsx
deleted file mode 100644
index 8a9480f90..000000000
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageButton.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { NewButton, NewIcon } from "@thunderstore/cyberstorm";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faFlagSwallowtail } from "@fortawesome/pro-solid-svg-icons";
-
-export function ReportPackageButton(props: { onClick: () => void }) {
- return (
-
-
-
-
-
- );
-}
-
-ReportPackageButton.displayName = "ReportPackageButton";
diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageModal.tsx b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageModal.tsx
deleted file mode 100644
index c3b54c2a0..000000000
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageModal.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Modal } from "@thunderstore/cyberstorm";
-
-import "./ReportPackage.css";
-
-interface ReportPackageModalProps {
- isOpen: boolean;
- onOpenChange: (isOpen: boolean) => void;
- children: React.ReactNode;
-}
-
-export function ReportPackageModal(props: ReportPackageModalProps) {
- return (
-
- {props.children}
-
- );
-}
-
-ReportPackageModal.displayName = "ReportPackageModal";
diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageSubmitted.tsx b/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageSubmitted.tsx
deleted file mode 100644
index a046b8db8..000000000
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/ReportPackageSubmitted.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { faFaceSaluting } from "@fortawesome/pro-light-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-import { Modal, NewButton, NewIcon } from "@thunderstore/cyberstorm";
-
-export function ReportPackageSubmitted(props: { closeModal: () => void }) {
- return (
- <>
-
-
-
-
-
-
- Thank you for your report
-
- We've received your report and will review the content shortly.
-
- Your feedback helps keep our community safe.
-
-
-
-
- Close
-
-
- >
- );
-}
-
-ReportPackageSubmitted.displayName = "ReportPackageSubmitted";
diff --git a/apps/cyberstorm-remix/app/p/components/ReportPackage/useReportPackage.tsx b/apps/cyberstorm-remix/app/p/components/ReportPackage/useReportPackage.tsx
deleted file mode 100644
index 8fb2b5019..000000000
--- a/apps/cyberstorm-remix/app/p/components/ReportPackage/useReportPackage.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useEffect, useState } from "react";
-
-import {
- ReportPackageForm,
- type ReportPackageFormProps,
-} from "./ReportPackageForm";
-import { ReportPackageButton } from "./ReportPackageButton";
-import { ReportPackageModal } from "./ReportPackageModal";
-import { ReportPackageSubmitted } from "./ReportPackageSubmitted";
-
-export function useReportPackage(formProps: Promise) {
- const [isOpen, setIsOpen] = useState(false);
- const [isSubmitted, setIsSubmitted] = useState(false);
- const [error, setError] = useState(null);
-
- const onOpenChange = (isOpen: boolean) => {
- setIsOpen(isOpen);
- setIsSubmitted(false);
- setError(null);
- };
-
- const [props, setProps] = useState(null);
-
- async function awaitAndSetProps() {
- if (!props) {
- setProps(await formProps);
- }
- }
-
- useEffect(() => {
- awaitAndSetProps();
- }, [formProps, props, awaitAndSetProps]);
-
- const button = onOpenChange(true)} />;
-
- const extraProps = { error, onOpenChange, setError, setIsSubmitted };
- const form = props && ;
-
- const done = (
- onOpenChange(false)} />
- );
-
- const modal = (
-
- {isSubmitted ? done : form}
-
- );
-
- return {
- ReportPackageButton: button,
- ReportPackageModal: modal,
- };
-}
diff --git a/apps/cyberstorm-remix/app/p/packageListing.css b/apps/cyberstorm-remix/app/p/packageListing.css
index 5f932c86f..65b0997e0 100644
--- a/apps/cyberstorm-remix/app/p/packageListing.css
+++ b/apps/cyberstorm-remix/app/p/packageListing.css
@@ -264,6 +264,13 @@
width: 100%;
}
+ .package-listing__narrow-other-actions {
+ display: flex;
+ flex-direction: row;
+ gap: var(--gap-xs);
+ width: 100%;
+ }
+
@media (width < 41rem) {
.package-listing__actions {
position: unset;
diff --git a/apps/cyberstorm-remix/app/p/packageListing.tsx b/apps/cyberstorm-remix/app/p/packageListing.tsx
index 51d463b49..b66e1c787 100644
--- a/apps/cyberstorm-remix/app/p/packageListing.tsx
+++ b/apps/cyberstorm-remix/app/p/packageListing.tsx
@@ -33,7 +33,6 @@ import { faArrowUpRight, faLips } from "@fortawesome/pro-solid-svg-icons";
import { CopyButton } from "app/commonComponents/CopyButton/CopyButton";
import { PageHeader } from "app/commonComponents/PageHeader/PageHeader";
import TeamMembers from "app/p/components/TeamMembers/TeamMembers";
-import { useReportPackage } from "app/p/components/ReportPackage/useReportPackage";
import { type OutletContextShape } from "app/root";
import { isPromise } from "cyberstorm/utils/typeChecks";
import {
@@ -73,6 +72,10 @@ import {
import { ApiAction } from "@thunderstore/ts-api-react-actions";
import "./packageListing.css";
+import {
+ ReportPackage,
+ ReportPackageButton,
+} from "./components/ReportPackage/ReportPackage";
type PackageListingOutletContext = OutletContextShape & {
packageDownloadUrl?: string;
@@ -181,15 +184,6 @@ export default function PackageListing() {
const [isLiked, setIsLiked] = useState(false);
const toast = useToast();
- const { ReportPackageButton, ReportPackageModal } = useReportPackage(
- Promise.resolve(listing).then((listingData) => ({
- community: listingData.community_identifier,
- namespace: listingData.namespace,
- package: listingData.name,
- config,
- }))
- );
-
const fetchAndSetRatedPackages = async () => {
const rp = await dapper.getRatedPackages();
if (isPromise(listing)) {
@@ -426,22 +420,34 @@ export default function PackageListing() {
- Loading...
}>
-
- {(resolvedValue) => (
-
- )}
-
-
-
- {ReportPackageButton}
+
+
Loading...}>
+
+ {(resolvedValue) => (
+
+ )}
+
+
+
}>
+
+ {(resolvedValue) => (
+
+ )}
+
+
+
-
- {ReportPackageButton}
+ }>
+
+ {(resolvedValue) => (
+
+ )}
+
+
-
- {ReportPackageModal}
>
);
}
diff --git a/apps/cyberstorm-remix/cyberstorm/utils/StrongForm/useStrongForm.ts b/apps/cyberstorm-remix/cyberstorm/utils/StrongForm/useStrongForm.ts
index 7c8408b78..7780633d9 100644
--- a/apps/cyberstorm-remix/cyberstorm/utils/StrongForm/useStrongForm.ts
+++ b/apps/cyberstorm-remix/cyberstorm/utils/StrongForm/useStrongForm.ts
@@ -126,6 +126,7 @@ export function useStrongForm<
) as SubmissionError
);
setInputErrors(error.error.formErrors as InputErrors);
+ throw error;
} else if (error instanceof RequestQueryParamsParseError) {
setSubmitError(
new Error(
@@ -133,6 +134,7 @@ export function useStrongForm<
) as SubmissionError
);
setInputErrors(error.error.formErrors as InputErrors);
+ throw error;
} else if (error instanceof ParseError) {
setSubmitError(
new Error(
@@ -150,6 +152,7 @@ export function useStrongForm<
if (props.onSubmitError) {
props.onSubmitError(error as SubmissionError);
}
+ setSubmitError((prev) => prev ?? (error as SubmissionError));
throw error;
} finally {
setSubmitting(false);