1+ import "./ReportPackage.css" ;
12import { useReducer , useState } from "react" ;
23
34import {
45 Modal ,
56 NewAlert ,
67 NewButton ,
8+ NewIcon ,
79 NewSelect ,
810 NewTextInput ,
11+ useToast ,
912 type SelectOption ,
1013} from "@thunderstore/cyberstorm" ;
1114import {
1215 type RequestConfig ,
1316 type PackageListingReportRequestData ,
1417 packageListingReport ,
1518} from "@thunderstore/thunderstore-api" ;
19+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
1620
1721import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm" ;
22+ import {
23+ faFaceSaluting ,
24+ faFlagSwallowtail ,
25+ } from "@fortawesome/pro-solid-svg-icons" ;
26+
27+ export function ReportPackageButton (
28+ props : React . HTMLAttributes < HTMLButtonElement >
29+ ) {
30+ return (
31+ < NewButton
32+ tooltipText = "Report Package"
33+ csVariant = "secondary"
34+ csModifiers = { [ "only-icon" ] }
35+ { ...props }
36+ >
37+ < NewIcon csMode = "inline" noWrapper >
38+ < FontAwesomeIcon icon = { faFlagSwallowtail } />
39+ </ NewIcon >
40+ </ NewButton >
41+ ) ;
42+ }
43+
44+ ReportPackageButton . displayName = "ReportPackageButton" ;
1845
1946const reportOptions : SelectOption < PackageListingReportRequestData [ "reason" ] > [ ] =
2047 [
@@ -27,29 +54,20 @@ const reportOptions: SelectOption<PackageListingReportRequestData["reason"]>[] =
2754 { value : "Other" , label : "Other" } ,
2855 ] ;
2956
30- export interface ReportPackageFormProps {
57+ export interface ReportPackageProps {
3158 community : string ;
3259 namespace : string ;
3360 package : string ;
3461 config : ( ) => RequestConfig ;
3562}
3663
37- interface ReportPackageFormFullProps extends ReportPackageFormProps {
38- error : string | null ;
39- onOpenChange : ( isOpen : boolean ) => void ;
40- setError : ( error : string | null ) => void ;
41- setIsSubmitted : ( isSubmitted : boolean ) => void ;
42- }
64+ export function ReportPackage ( props : ReportPackageProps ) {
65+ const { config, ...requestParams } = props ;
66+
67+ const [ submitted , setSubmitted ] = useState ( false ) ;
68+ const [ modalOpen , setModalOpen ] = useState ( false ) ;
4369
44- export function ReportPackageForm ( props : ReportPackageFormFullProps ) {
45- const {
46- config,
47- onOpenChange,
48- setIsSubmitted,
49- error,
50- setError,
51- ...requestParams
52- } = props ;
70+ const toast = useToast ( ) ;
5371
5472 function formFieldUpdateAction (
5573 state : PackageListingReportRequestData ,
@@ -95,21 +113,24 @@ export function ReportPackageForm(props: ReportPackageFormFullProps) {
95113 inputs : formInputs ,
96114 submitor,
97115 onSubmitSuccess : ( ) => {
98- setIsSubmitted ( true ) ;
99- setError ( null ) ;
116+ setSubmitted ( true ) ;
100117 } ,
101118 onSubmitError : ( error ) => {
102119 let message = `Error occurred: ${ error . message || "Unknown error" } ` ;
103120 if ( error . message === "401: Unauthorized" ) {
104121 message = "You must be logged in to report a package." ;
105122 }
106- setError ( message ) ;
123+ toast . addToast ( {
124+ csVariant : "danger" ,
125+ children : message ,
126+ duration : 8000 ,
127+ } ) ;
107128 } ,
108129 } ) ;
109130
110- return (
131+ const form = (
111132 < >
112- < Modal . Body >
133+ < Modal . Body className = "report-package__body" >
113134 < div className = "report-package__block" >
114135 < label htmlFor = "reason" className = "report-package__label" >
115136 Reason
@@ -147,22 +168,91 @@ export function ReportPackageForm(props: ReportPackageFormFullProps) {
147168 rootClasses = "report-package__textarea"
148169 />
149170 </ div >
150- { error && (
171+ { strongForm . inputErrors ||
172+ strongForm . refineError ||
173+ strongForm . submitError ? (
151174 < div className = "report-package__block" >
152- < NewAlert csVariant = "danger" > { error } </ NewAlert >
175+ { strongForm . inputErrors ? (
176+ < NewAlert csVariant = "danger" >
177+ { Object . entries ( strongForm . inputErrors ) . map ( ( [ key , value ] ) => (
178+ < div key = { key } >
179+ < strong > { key } :</ strong > { " " }
180+ { Array . isArray ( value ) ? value . join ( ", " ) : value }
181+ </ div >
182+ ) ) }
183+ </ NewAlert >
184+ ) : null }
185+ { strongForm . refineError ? (
186+ < NewAlert csVariant = "danger" >
187+ Error while refining: { strongForm . refineError . message }
188+ </ NewAlert >
189+ ) : null }
190+ { strongForm . submitError ? (
191+ < NewAlert csVariant = "danger" >
192+ Error while submitting: { strongForm . submitError . message }
193+ </ NewAlert >
194+ ) : null }
153195 </ div >
154- ) }
196+ ) : null }
155197 </ Modal . Body >
156198 < Modal . Footer >
157- < NewButton csVariant = "secondary" onClick = { ( ) => onOpenChange ( false ) } >
158- Cancel
159- </ NewButton >
199+ < Modal . Close asChild >
200+ < NewButton csVariant = "secondary" > Cancel</ NewButton >
201+ </ Modal . Close >
160202 < NewButton csVariant = "accent" onClick = { strongForm . submit } >
161203 Send report
162204 </ NewButton >
163205 </ Modal . Footer >
164206 </ >
165207 ) ;
208+
209+ const done = (
210+ < >
211+ < Modal . Body className = "report-package-body report-package-body--centered" >
212+ < div className = "report-package__block " >
213+ < NewIcon
214+ csMode = "inline"
215+ noWrapper
216+ rootClasses = "report-package__submitted-icon"
217+ >
218+ < FontAwesomeIcon icon = { faFaceSaluting } />
219+ </ NewIcon >
220+ </ div >
221+ < h3 className = "report-package__heading" > Thank you for your report</ h3 >
222+ < p className = "report-package__paragraph" >
223+ We've received your report and will review the content shortly.
224+ < br />
225+ Your feedback helps keep our community safe.
226+ </ p >
227+ </ Modal . Body >
228+ < Modal . Footer >
229+ < Modal . Close asChild >
230+ < NewButton csVariant = "secondary" > Close</ NewButton >
231+ </ Modal . Close >
232+ </ Modal . Footer >
233+ </ >
234+ ) ;
235+
236+ return (
237+ < Modal
238+ titleContent = "Report Package"
239+ csSize = "small"
240+ disableBody
241+ onOpenChange = { ( isOpen ) => {
242+ if ( modalOpen && submitted && ! isOpen ) {
243+ // If the modal is being closed after a successful submission,
244+ // reset the form state.
245+ updateFormFieldState ( { field : "reason" , value : "Other" } ) ;
246+ updateFormFieldState ( { field : "description" , value : "" } ) ;
247+ setSubmitted ( false ) ;
248+ }
249+ setModalOpen ( isOpen ) ;
250+ } }
251+ trigger = { < ReportPackageButton /> }
252+ >
253+ { submitted ? done : form }
254+ </ Modal >
255+ ) ;
166256}
167257
168- ReportPackageForm . displayName = "ReportPackageForm " ;
258+ ReportPackage . displayName = "ReportPackage " ;
0 commit comments