@rssa-project/study-template 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +49 -0
  3. package/dist/App.d.ts +2 -0
  4. package/dist/components/CodeInput.d.ts +7 -0
  5. package/dist/components/ContinueFormModal.d.ts +9 -0
  6. package/dist/components/ErrorBoundary.d.ts +15 -0
  7. package/dist/components/LoadingText.d.ts +6 -0
  8. package/dist/components/PaginatedDataViewer.d.ts +9 -0
  9. package/dist/components/Select.d.ts +7 -0
  10. package/dist/components/TestFeedbackModal.d.ts +10 -0
  11. package/dist/components/TestModeConfirmation.d.ts +7 -0
  12. package/dist/components/TestModeIndicator.d.ts +6 -0
  13. package/dist/components/TestModeToast.d.ts +10 -0
  14. package/dist/components/loadingscreen/LoadingScreen.d.ts +7 -0
  15. package/dist/components/moviegallery/MovieCard.d.ts +7 -0
  16. package/dist/components/moviegallery/StarRating.d.ts +6 -0
  17. package/dist/components/warningDialog.d.ts +12 -0
  18. package/dist/constants.d.ts +11 -0
  19. package/dist/contexts/NextButtonContext.d.ts +12 -0
  20. package/dist/contexts/NextButtonControlProvider.d.ts +3 -0
  21. package/dist/contexts/StudyUrlParamsContext.d.ts +12 -0
  22. package/dist/contexts/pageCompletionContext.d.ts +4 -0
  23. package/dist/contexts/stepCompletionContext.d.ts +4 -0
  24. package/dist/hooks/useDebounce.d.ts +1 -0
  25. package/dist/hooks/useNextButtonControl.d.ts +1 -0
  26. package/dist/hooks/usePageCompletion.d.ts +7 -0
  27. package/dist/hooks/useStepCompletion.d.ts +7 -0
  28. package/dist/index.d.ts +26 -0
  29. package/dist/layouts/StudyFooter.d.ts +2 -0
  30. package/dist/layouts/StudyHeader.d.ts +5 -0
  31. package/dist/layouts/StudyLayout.d.ts +6 -0
  32. package/dist/layouts/WelcomeFooter.d.ts +8 -0
  33. package/dist/layouts/templates/ContentBlock.d.ts +7 -0
  34. package/dist/layouts/templates/ItemBlock.d.ts +11 -0
  35. package/dist/layouts/templates/SurveyTemplate.d.ts +6 -0
  36. package/dist/main.d.ts +0 -0
  37. package/dist/pages/ConsentPage.d.ts +21 -0
  38. package/dist/pages/DemographicsPage.d.ts +2 -0
  39. package/dist/pages/FeedbackPage.d.ts +16 -0
  40. package/dist/pages/FinalPage.d.ts +3 -0
  41. package/dist/pages/MovieRatingPage.d.ts +7 -0
  42. package/dist/pages/StudyExitPage.d.ts +3 -0
  43. package/dist/pages/SurveyPage.d.ts +2 -0
  44. package/dist/pages/WelcomePage.d.ts +18 -0
  45. package/dist/res/country_state.json.d.ts +970 -0
  46. package/dist/routes/RouteWrapper.d.ts +13 -0
  47. package/dist/rssa-study-template.es.js +8989 -0
  48. package/dist/types/rssa.types.d.ts +142 -0
  49. package/dist/types/study.types.d.ts +5 -0
  50. package/dist/utils/constants.d.ts +11 -0
  51. package/dist/vite.svg +1 -0
  52. package/package.json +83 -0
package/LICENSE ADDED
@@ -0,0 +1 @@
1
+ MIT License
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # RSSA Study Template (@rssa-project/study-template)
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@rssa-project/study-template.svg)](https://www.npmjs.com/package/@rssa-project/study-template)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A React component library providing standard layouts, pages, and hooks for building research studies on the RSSA Platform. It creates a consistent UI and logic flow (consent -> survey -> stimuli -> feedback) across different RSSA studies.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @rssa-project/study-template
12
+ ```
13
+
14
+ ## Quick Start
15
+
16
+ Wrap your main router with the `RouteWrapper`, ensuring you pass a component map mapping step types to your page components.
17
+
18
+ ```tsx
19
+ import { RouteWrapper, WelcomePage, SurveyPage, FinalPage } from '@rssa-project/study-template';
20
+ import UserCustomPage from './UserCustomPage';
21
+
22
+ // Map 'step_type' from your study config to React components
23
+ const componentMap = {
24
+ welcome: WelcomePage,
25
+ survey: SurveyPage,
26
+ custom_task: UserCustomPage,
27
+ completion: FinalPage,
28
+ };
29
+
30
+ function App() {
31
+ return (
32
+ <Router>
33
+ {/* RouteWrapper handles navigation logic based on study state */}
34
+ <RouteWrapper componentMap={componentMap} WelcomePage={WelcomePage} />
35
+ </Router>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Core Features
41
+
42
+ - **Standard Pages**: `ConsentPage`, `SurveyPage`, `MovieRatingPage`, `DemographicsPage`.
43
+ - **Hooks**: `useNextButtonControl`, `useStepCompletion`.
44
+ - **Contexts**: Handles participant state and navigation flow automatically.
45
+
46
+ ## Requirements
47
+
48
+ - React 18+
49
+ - `@rssa-project/api` (Peer Dependency)
package/dist/App.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare function App(): import("react/jsx-runtime").JSX.Element;
2
+ export default App;
@@ -0,0 +1,7 @@
1
+ interface CodeInputProps {
2
+ value: string;
3
+ onChange: (value: string) => void;
4
+ length?: number;
5
+ }
6
+ declare const CodeInput: React.FC<CodeInputProps>;
7
+ export default CodeInput;
@@ -0,0 +1,9 @@
1
+ declare const ContinueFormModal: React.FC<{
2
+ title: string;
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ onSubmit: (resumeCode: string) => void;
6
+ isSubmitting: boolean;
7
+ submitButtonText: string;
8
+ }>;
9
+ export default ContinueFormModal;
@@ -0,0 +1,15 @@
1
+ import { Component, ErrorInfo, ReactNode } from 'react';
2
+ interface Props {
3
+ children: ReactNode;
4
+ }
5
+ interface State {
6
+ hasError: boolean;
7
+ errorMessage: string;
8
+ }
9
+ declare class ErrorBoundary extends Component<Props, State> {
10
+ state: State;
11
+ static getDerivedStateFromError(error: Error): State;
12
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
13
+ render(): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
14
+ }
15
+ export default ErrorBoundary;
@@ -0,0 +1,6 @@
1
+ import { default as React } from 'react';
2
+ interface LoadingTextProps {
3
+ text: string;
4
+ }
5
+ declare const LoadingText: React.FC<LoadingTextProps>;
6
+ export default LoadingText;
@@ -0,0 +1,9 @@
1
+ interface PaginatedResourceViewerProps<T> {
2
+ apiResourceTag: string;
3
+ limit?: number;
4
+ children: (data: T[], selectedItem: T | null, handleItemClick: (item: T) => void) => React.ReactNode;
5
+ }
6
+ declare const PaginatedResourceViewer: <T extends {
7
+ id: string;
8
+ }>({ apiResourceTag, limit, children, }: PaginatedResourceViewerProps<T>) => import("react/jsx-runtime").JSX.Element;
9
+ export default PaginatedResourceViewer;
@@ -0,0 +1,7 @@
1
+ declare const Select: ({ onChange, children, placeholder, className, }: {
2
+ onChange: (value: string | boolean | number | null) => void;
3
+ children: React.ReactNode[];
4
+ placeholder?: string;
5
+ className?: string;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export default Select;
@@ -0,0 +1,10 @@
1
+ import { StudyStep } from '../types/rssa.types';
2
+ import { ToastType } from './TestModeToast';
3
+ interface TestFeedbackModalProps {
4
+ isOpen: boolean;
5
+ onClose: () => void;
6
+ studyStep?: StudyStep;
7
+ onShowToast: (message: string, type: ToastType) => void;
8
+ }
9
+ declare const TestFeedbackModal: React.FC<TestFeedbackModalProps>;
10
+ export default TestFeedbackModal;
@@ -0,0 +1,7 @@
1
+ interface TestModeConfirmationProps {
2
+ isOpen: boolean;
3
+ onConfirm: () => void;
4
+ onCancel: () => void;
5
+ }
6
+ declare const TestModeConfirmation: React.FC<TestModeConfirmationProps>;
7
+ export default TestModeConfirmation;
@@ -0,0 +1,6 @@
1
+ import { StudyStep } from '../types/rssa.types';
2
+ interface TestModeIndicatorProps {
3
+ studyStep?: StudyStep;
4
+ }
5
+ declare const TestModeIndicator: React.FC<TestModeIndicatorProps>;
6
+ export default TestModeIndicator;
@@ -0,0 +1,10 @@
1
+ export type ToastType = "success" | "error";
2
+ interface TestModeToastProps {
3
+ show: boolean;
4
+ message: string;
5
+ type: ToastType;
6
+ onClose: () => void;
7
+ duration?: number;
8
+ }
9
+ declare const TestModeToast: React.FC<TestModeToastProps>;
10
+ export default TestModeToast;
@@ -0,0 +1,7 @@
1
+ interface LoadingScreenProps {
2
+ loading: boolean;
3
+ message: string;
4
+ byline?: string;
5
+ }
6
+ declare const LoadingScreen: React.FC<LoadingScreenProps>;
7
+ export default LoadingScreen;
@@ -0,0 +1,7 @@
1
+ import { MovieDetails, RatedItem } from '../../types/rssa.types';
2
+ declare const MovieCard: ({ movie, userRating, onClick, }: {
3
+ movie: MovieDetails;
4
+ userRating: RatedItem | undefined;
5
+ onClick: () => void;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export default MovieCard;
@@ -0,0 +1,6 @@
1
+ declare const StarRating: ({ initialRating, onRatingChange, maxStars, }: {
2
+ initialRating: number;
3
+ onRatingChange: (newRating: number) => void;
4
+ maxStars: number;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ export default StarRating;
@@ -0,0 +1,12 @@
1
+ interface WarningDialogProps {
2
+ show: boolean;
3
+ title: string;
4
+ message: string;
5
+ onClose: (show: boolean) => void;
6
+ confirmCallback?: () => void;
7
+ confirmText?: string;
8
+ cancelCallback?: () => void;
9
+ disableHide?: boolean;
10
+ }
11
+ export declare const WarningDialog: React.FC<WarningDialogProps>;
12
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare const STRINGS: {
2
+ WINDOW_TOO_SMALL: string;
3
+ STUDY_ERROR: string;
4
+ };
5
+ export declare const customBreakpoints: {
6
+ xl: number;
7
+ xxl: number;
8
+ xxxl: number;
9
+ xl4: number;
10
+ };
11
+ export declare const RETRY_DELAYS_MS: number[];
@@ -0,0 +1,12 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ export interface NextButtonControl {
3
+ label: string;
4
+ action: () => void;
5
+ isDisabled: boolean;
6
+ }
7
+ export declare const defaultControl: NextButtonControl;
8
+ export interface NextButtonContextType {
9
+ setButtonControl: Dispatch<SetStateAction<NextButtonControl>>;
10
+ buttonControl: NextButtonControl;
11
+ }
12
+ export declare const NextButtonContext: import('react').Context<NextButtonContextType | null>;
@@ -0,0 +1,3 @@
1
+ export declare const NextButtonControlProvider: ({ children, }: {
2
+ children: React.ReactNode;
3
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { default as React, ReactNode } from 'react';
2
+ interface StudyUrlParams {
3
+ participantTypeKey: string;
4
+ externalId: string;
5
+ isTestMode: boolean;
6
+ }
7
+ export declare const useStudyUrlParams: () => StudyUrlParams;
8
+ export declare const StudyUrlParamsProvider: React.FC<{
9
+ children: ReactNode;
10
+ params: StudyUrlParams;
11
+ }>;
12
+ export {};
@@ -0,0 +1,4 @@
1
+ import { ReactNode } from 'react';
2
+ export declare const PageCompletionProvider: ({ children, }: {
3
+ children: ReactNode;
4
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { ReactNode } from 'react';
2
+ export declare const StepCompletionProvider: ({ children, }: {
3
+ children: ReactNode;
4
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function useDebounce<T>(value: T, delay: number): T;
@@ -0,0 +1 @@
1
+ export declare const useNextButtonControl: () => import('..').NextButtonContextType;
@@ -0,0 +1,7 @@
1
+ interface PageCompletionContextType {
2
+ isPageComplete: boolean;
3
+ setIsPageComplete: (isComplete: boolean) => void;
4
+ }
5
+ export declare const PageCompletionContext: import('react').Context<PageCompletionContextType | undefined>;
6
+ export declare const usePageCompletion: () => PageCompletionContextType;
7
+ export {};
@@ -0,0 +1,7 @@
1
+ interface StepCompletionContextType {
2
+ isStepComplete: boolean;
3
+ setIsStepComplete: (isComplete: boolean) => void;
4
+ }
5
+ export declare const StepCompletionContext: import('react').Context<StepCompletionContextType | undefined>;
6
+ export declare const useStepCompletion: () => StepCompletionContextType;
7
+ export {};
@@ -0,0 +1,26 @@
1
+ export { default as RouteWrapper } from './routes/RouteWrapper';
2
+ export { default as StudyLayout } from './layouts/StudyLayout';
3
+ export { default as LoadingScreen } from './components/loadingscreen/LoadingScreen';
4
+ export { default as ErrorBoundary } from './components/ErrorBoundary';
5
+ export * from './types/rssa.types.ts';
6
+ export * from './types/study.types.ts';
7
+ export * from './hooks/useStepCompletion';
8
+ export * from './hooks/useNextButtonControl';
9
+ export * from './hooks/usePageCompletion';
10
+ export * from './contexts/stepCompletionContext';
11
+ export * from './contexts/NextButtonControlProvider';
12
+ export * from './contexts/NextButtonContext';
13
+ export * from './contexts/pageCompletionContext';
14
+ export { default as SurveyPage } from './pages/SurveyPage';
15
+ export { default as SurveyTemplate } from './layouts/templates/SurveyTemplate';
16
+ export { default as WelcomePage } from './pages/WelcomePage';
17
+ export { default as ConsentPage } from './pages/ConsentPage';
18
+ export { default as MovieRatingPage } from './pages/MovieRatingPage';
19
+ export { default as MovieCard } from './components/moviegallery/MovieCard';
20
+ export { default as StarRating } from './components/moviegallery/StarRating';
21
+ export { default as DemographicsPage } from './pages/DemographicsPage';
22
+ export { default as FeedbackPage } from './pages/FeedbackPage';
23
+ export { default as LoadingText } from './components/LoadingText';
24
+ export { default as FinalPage } from './pages/FinalPage';
25
+ export { WarningDialog } from './components/warningDialog';
26
+ export * from './hooks/useDebounce';
@@ -0,0 +1,2 @@
1
+ export declare const Footer: React.FC;
2
+ export default Footer;
@@ -0,0 +1,5 @@
1
+ export declare const Header: React.FC<{
2
+ title: string;
3
+ content: string;
4
+ }>;
5
+ export default Header;
@@ -0,0 +1,6 @@
1
+ import { StudyStep } from '../types/rssa.types';
2
+ interface StudyLayoutProps {
3
+ stepApiData: StudyStep | undefined;
4
+ }
5
+ declare const StudyLayout: ({ stepApiData }: StudyLayoutProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default StudyLayout;
@@ -0,0 +1,8 @@
1
+ export declare const WelcomeFooter: React.FC<{
2
+ onStudyStart: () => void;
3
+ onStudyContinue: (showForm: boolean) => void;
4
+ disabled?: boolean;
5
+ text?: string;
6
+ loading?: false;
7
+ }>;
8
+ export default WelcomeFooter;
@@ -0,0 +1,7 @@
1
+ import { PageContent } from '../../types/rssa.types';
2
+ interface ContentBlockProps {
3
+ content: PageContent;
4
+ onComplete: (contentId: string) => void;
5
+ }
6
+ declare const ContentBlock: React.FC<ContentBlockProps>;
7
+ export default ContentBlock;
@@ -0,0 +1,11 @@
1
+ import { ScaleLevel, SurveyConstructItem, SurveyItemResponse } from '../../types/rssa.types';
2
+ interface ItemBlockProps {
3
+ contextTag: string;
4
+ pageId: string;
5
+ item: SurveyConstructItem;
6
+ initialResponse: SurveyItemResponse | undefined;
7
+ scaleLevels: ScaleLevel[];
8
+ onSelected: (itemId: string) => void;
9
+ }
10
+ declare const ItemBlock: React.FC<ItemBlockProps>;
11
+ export default ItemBlock;
@@ -0,0 +1,6 @@
1
+ import { SurveyPageType } from '../../types/rssa.types';
2
+ interface SurveyTemplateProps {
3
+ surveyPage: SurveyPageType;
4
+ }
5
+ declare const SurveyTemplate: React.FC<SurveyTemplateProps>;
6
+ export default SurveyTemplate;
package/dist/main.d.ts ADDED
File without changes
@@ -0,0 +1,21 @@
1
+ export interface BaseParticipant {
2
+ participant_type_key: string;
3
+ external_id: string;
4
+ current_step_id: string;
5
+ current_page_id?: string | null;
6
+ }
7
+ export interface ParticipantTokenObject {
8
+ resume_code: string;
9
+ token: string;
10
+ }
11
+ interface ConsentPageProps {
12
+ children: React.ReactNode;
13
+ participantTypeKey?: string;
14
+ participantTypeId?: string;
15
+ externalId?: string;
16
+ onConsentSuccess?: (token: string, resumeCode: string) => void;
17
+ title?: string;
18
+ itemTitle?: string;
19
+ }
20
+ declare const ConsentPage: React.FC<ConsentPageProps>;
21
+ export default ConsentPage;
@@ -0,0 +1,2 @@
1
+ declare const DemographicsPage: React.FC;
2
+ export default DemographicsPage;
@@ -0,0 +1,16 @@
1
+ import { default as React } from 'react';
2
+ export type Feedback = {
3
+ feedback_text: string;
4
+ feedback_type: string;
5
+ feedback_category: string;
6
+ study_step_id: string;
7
+ context_tag: string;
8
+ };
9
+ export type TextResponsePayload = {
10
+ study_step_id: string;
11
+ study_step_page_id?: string;
12
+ context_tag: string;
13
+ response_text: string;
14
+ };
15
+ declare const FeedbackPage: React.FC;
16
+ export default FeedbackPage;
@@ -0,0 +1,3 @@
1
+ import { default as React } from 'react';
2
+ declare const FinalPage: React.FC;
3
+ export default FinalPage;
@@ -0,0 +1,7 @@
1
+ import { default as React } from 'react';
2
+ interface MovieRatingPageProps {
3
+ minRatingCount?: number;
4
+ itemsPerPage?: number;
5
+ }
6
+ declare const MovieRatingPage: React.FC<MovieRatingPageProps>;
7
+ export default MovieRatingPage;
@@ -0,0 +1,3 @@
1
+ import { default as React } from 'react';
2
+ declare const StudyExitPage: React.FC;
3
+ export default StudyExitPage;
@@ -0,0 +1,2 @@
1
+ declare const SurveyPage: React.FC;
2
+ export default SurveyPage;
@@ -0,0 +1,18 @@
1
+ export interface ResumePayload {
2
+ resume_code: string;
3
+ }
4
+ export interface ResumeResponse {
5
+ current_step_id: string;
6
+ current_page_id: string;
7
+ token: string;
8
+ }
9
+ interface WelcomePageProps {
10
+ isStudyReady?: boolean;
11
+ onStudyStart?: () => void;
12
+ title?: string;
13
+ subtitle?: string;
14
+ ContentComponent?: React.FC;
15
+ children?: React.ReactNode;
16
+ }
17
+ declare const WelcomePage: React.FC<WelcomePageProps>;
18
+ export default WelcomePage;