@stone-js/starters 0.8.3
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.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/basic-react-declarative/LICENSE +21 -0
- package/basic-react-declarative/README.md +39 -0
- package/basic-react-declarative/app/Application.tsx +89 -0
- package/basic-react-declarative/assets/css/index.css +26 -0
- package/basic-react-declarative/package.json +39 -0
- package/basic-react-declarative/public/logo.png +0 -0
- package/basic-react-declarative/tests/Application.spec.ts +96 -0
- package/basic-react-declarative/tests/__snapshots__/Application.spec.ts.snap +3 -0
- package/basic-react-declarative/tsconfig.json +33 -0
- package/basic-react-declarative/vitest.config.ts +24 -0
- package/basic-react-imperative/LICENSE +21 -0
- package/basic-react-imperative/README.md +39 -0
- package/basic-react-imperative/app/Application.tsx +89 -0
- package/basic-react-imperative/assets/css/index.css +26 -0
- package/basic-react-imperative/package.json +39 -0
- package/basic-react-imperative/public/logo.png +0 -0
- package/basic-react-imperative/tests/Application.spec.ts +80 -0
- package/basic-react-imperative/tests/__snapshots__/Application.spec.ts.snap +3 -0
- package/basic-react-imperative/tsconfig.json +33 -0
- package/basic-react-imperative/vitest.config.ts +24 -0
- package/basic-service-declarative/LICENSE +21 -0
- package/basic-service-declarative/README.md +39 -0
- package/basic-service-declarative/app/Application.ts +56 -0
- package/basic-service-declarative/package.json +34 -0
- package/basic-service-declarative/tests/Application.spec.ts +60 -0
- package/basic-service-declarative/tsconfig.json +25 -0
- package/basic-service-declarative/vitest.config.ts +24 -0
- package/basic-service-imperative/LICENSE +21 -0
- package/basic-service-imperative/README.md +39 -0
- package/basic-service-imperative/app/Application.ts +60 -0
- package/basic-service-imperative/package.json +34 -0
- package/basic-service-imperative/tests/Application.spec.ts +52 -0
- package/basic-service-imperative/tsconfig.json +25 -0
- package/basic-service-imperative/vitest.config.ts +24 -0
- package/continuum-showcase/README.md +44 -0
- package/continuum-showcase/app/env.d.ts +34 -0
- package/continuum-showcase/app/layouts/MainLayout.tsx +20 -0
- package/continuum-showcase/app/pages/BlogPostPage.tsx +62 -0
- package/continuum-showcase/app/pages/HomePage.tsx +58 -0
- package/continuum-showcase/package.json +25 -0
- package/continuum-showcase/stone.config.mjs +20 -0
- package/full-react-declarative/.env.example +1 -0
- package/full-react-declarative/.env.public.example +1 -0
- package/full-react-declarative/LICENSE +21 -0
- package/full-react-declarative/README.md +39 -0
- package/full-react-declarative/app/Application.ts +85 -0
- package/full-react-declarative/app/clients/AxiosClient.ts +136 -0
- package/full-react-declarative/app/clients/CommentClient.ts +61 -0
- package/full-react-declarative/app/clients/PostClient.ts +90 -0
- package/full-react-declarative/app/clients/SecurityClient.ts +66 -0
- package/full-react-declarative/app/clients/UserClient.ts +97 -0
- package/full-react-declarative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
- package/full-react-declarative/app/components/CommentForm/CommentForm.tsx +37 -0
- package/full-react-declarative/app/components/CommentItem/CommentItem.tsx +42 -0
- package/full-react-declarative/app/components/CommentWidget/CommentWidget.tsx +95 -0
- package/full-react-declarative/app/components/LoginForm/LoginForm.css +0 -0
- package/full-react-declarative/app/components/LoginForm/LoginForm.tsx +71 -0
- package/full-react-declarative/app/components/PostDetails/PostDetails.tsx +44 -0
- package/full-react-declarative/app/components/PostForm/PostForm.css +0 -0
- package/full-react-declarative/app/components/PostForm/PostForm.tsx +47 -0
- package/full-react-declarative/app/components/PostItem/PostItem.css +0 -0
- package/full-react-declarative/app/components/PostItem/PostItem.tsx +34 -0
- package/full-react-declarative/app/components/RegisterForm/RegisterForm.tsx +110 -0
- package/full-react-declarative/app/components/UserForm/UserForm.tsx +47 -0
- package/full-react-declarative/app/configurations/AppConfiguration.ts +17 -0
- package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
- package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +52 -0
- package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
- package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +53 -0
- package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
- package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +54 -0
- package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
- package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +53 -0
- package/full-react-declarative/app/errors/ForbiddenError.ts +11 -0
- package/full-react-declarative/app/errors/PostNotFoundError.ts +11 -0
- package/full-react-declarative/app/errors/UnauthorizedError.ts +11 -0
- package/full-react-declarative/app/errors/UserNotFoundError.ts +11 -0
- package/full-react-declarative/app/events/UserEvent.ts +18 -0
- package/full-react-declarative/app/layout/AppLayout/AppLayout.css +20 -0
- package/full-react-declarative/app/layout/AppLayout/AppLayout.tsx +101 -0
- package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
- package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.tsx +41 -0
- package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
- package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.tsx +39 -0
- package/full-react-declarative/app/middleware/AuthMiddleware.ts +85 -0
- package/full-react-declarative/app/models/Comment.ts +31 -0
- package/full-react-declarative/app/models/Post.ts +22 -0
- package/full-react-declarative/app/models/User.ts +62 -0
- package/full-react-declarative/app/pages/home/HomePage.tsx +44 -0
- package/full-react-declarative/app/pages/login/LoginPage.css +0 -0
- package/full-react-declarative/app/pages/login/LoginPage.tsx +73 -0
- package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.css +0 -0
- package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.tsx +67 -0
- package/full-react-declarative/app/pages/posts/PostPage/PostPage.tsx +60 -0
- package/full-react-declarative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +83 -0
- package/full-react-declarative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +77 -0
- package/full-react-declarative/app/pages/register/RegisterPage.tsx +68 -0
- package/full-react-declarative/app/pages/users/CreateUserPage.tsx +48 -0
- package/full-react-declarative/app/pages/users/ShowUserPage.tsx +62 -0
- package/full-react-declarative/app/pages/users/UpdateUserPage.tsx +57 -0
- package/full-react-declarative/app/pages/users/UserPage.tsx +57 -0
- package/full-react-declarative/app/providers/AppServiceProvider.ts +43 -0
- package/full-react-declarative/app/services/CommentService.ts +59 -0
- package/full-react-declarative/app/services/PostService.ts +108 -0
- package/full-react-declarative/app/services/SecurityService.ts +80 -0
- package/full-react-declarative/app/services/TokenService.ts +116 -0
- package/full-react-declarative/app/services/UserService.ts +126 -0
- package/full-react-declarative/app/utils.ts +17 -0
- package/full-react-declarative/assets/css/index.css +301 -0
- package/full-react-declarative/assets/img/logo.png +0 -0
- package/full-react-declarative/package.json +46 -0
- package/full-react-declarative/public/logo.png +0 -0
- package/full-react-declarative/public/vite.svg +1 -0
- package/full-react-declarative/stone.config.mjs +12 -0
- package/full-react-declarative/tsconfig.json +29 -0
- package/full-react-declarative/vitest.config.ts +24 -0
- package/full-react-imperative/.env.example +1 -0
- package/full-react-imperative/.env.public.example +1 -0
- package/full-react-imperative/LICENSE +21 -0
- package/full-react-imperative/README.md +39 -0
- package/full-react-imperative/app/Application.ts +79 -0
- package/full-react-imperative/app/clients/AxiosClient.ts +124 -0
- package/full-react-imperative/app/clients/CommentClient.ts +57 -0
- package/full-react-imperative/app/clients/PostClient.ts +86 -0
- package/full-react-imperative/app/clients/SecurityClient.ts +60 -0
- package/full-react-imperative/app/clients/UserClient.ts +93 -0
- package/full-react-imperative/app/clients/contracts/IAxiosClient.ts +97 -0
- package/full-react-imperative/app/clients/contracts/ICommentClient.ts +31 -0
- package/full-react-imperative/app/clients/contracts/IPostClient.ts +55 -0
- package/full-react-imperative/app/clients/contracts/ISecurityClient.ts +33 -0
- package/full-react-imperative/app/clients/contracts/IUserClient.ts +61 -0
- package/full-react-imperative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
- package/full-react-imperative/app/components/CommentForm/CommentForm.css +35 -0
- package/full-react-imperative/app/components/CommentForm/CommentForm.tsx +45 -0
- package/full-react-imperative/app/components/CommentItem/CommentItem.css +74 -0
- package/full-react-imperative/app/components/CommentItem/CommentItem.tsx +62 -0
- package/full-react-imperative/app/components/CommentWidget/CommentWidget.css +25 -0
- package/full-react-imperative/app/components/CommentWidget/CommentWidget.tsx +119 -0
- package/full-react-imperative/app/components/Dropdown/Dropdown.css +52 -0
- package/full-react-imperative/app/components/Dropdown/Dropdown.tsx +40 -0
- package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.css +62 -0
- package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.tsx +61 -0
- package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.css +25 -0
- package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.tsx +32 -0
- package/full-react-imperative/app/components/LoginForm/LoginForm.css +0 -0
- package/full-react-imperative/app/components/LoginForm/LoginForm.tsx +71 -0
- package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.css +41 -0
- package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.tsx +63 -0
- package/full-react-imperative/app/components/PostCard/PostCard.css +129 -0
- package/full-react-imperative/app/components/PostCard/PostCard.tsx +65 -0
- package/full-react-imperative/app/components/PostForm/PostForm.css +92 -0
- package/full-react-imperative/app/components/PostForm/PostForm.tsx +76 -0
- package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.css +65 -0
- package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.tsx +25 -0
- package/full-react-imperative/app/components/PostWidget/PostWidget.tsx +95 -0
- package/full-react-imperative/app/components/ProfileForm/ProfileForm.css +84 -0
- package/full-react-imperative/app/components/ProfileForm/ProfileForm.tsx +79 -0
- package/full-react-imperative/app/components/RegisterForm/RegisterForm.tsx +110 -0
- package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.css +32 -0
- package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.tsx +62 -0
- package/full-react-imperative/app/components/SettingsForm/SettingsForm.css +126 -0
- package/full-react-imperative/app/components/SettingsForm/SettingsForm.tsx +86 -0
- package/full-react-imperative/app/components/UserAvatar/UserAvatar.css +18 -0
- package/full-react-imperative/app/components/UserAvatar/UserAvatar.tsx +60 -0
- package/full-react-imperative/app/components/UserBadge/UserBadge.css +33 -0
- package/full-react-imperative/app/components/UserBadge/UserBadge.tsx +49 -0
- package/full-react-imperative/app/components/UserCard/UserCard.css +70 -0
- package/full-react-imperative/app/components/UserCard/UserCard.tsx +43 -0
- package/full-react-imperative/app/configurations/AppConfiguration.ts +19 -0
- package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
- package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +41 -0
- package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
- package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +42 -0
- package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
- package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +49 -0
- package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
- package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +42 -0
- package/full-react-imperative/app/errors/ForbiddenError.ts +11 -0
- package/full-react-imperative/app/errors/PostNotFoundError.ts +11 -0
- package/full-react-imperative/app/errors/UnauthorizedError.ts +11 -0
- package/full-react-imperative/app/errors/UserNotFoundError.ts +11 -0
- package/full-react-imperative/app/events/UserEvent.ts +18 -0
- package/full-react-imperative/app/layout/AppLayout/AppLayout.css +106 -0
- package/full-react-imperative/app/layout/AppLayout/AppLayout.tsx +48 -0
- package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
- package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.tsx +45 -0
- package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
- package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.tsx +43 -0
- package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.css +99 -0
- package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.tsx +44 -0
- package/full-react-imperative/app/middleware/AuthMiddleware.ts +56 -0
- package/full-react-imperative/app/models/Comment.ts +35 -0
- package/full-react-imperative/app/models/Post.ts +27 -0
- package/full-react-imperative/app/models/User.ts +68 -0
- package/full-react-imperative/app/pages/Settings/SettingsPage.tsx +23 -0
- package/full-react-imperative/app/pages/home/HomePage.tsx +58 -0
- package/full-react-imperative/app/pages/login/LoginPage.css +0 -0
- package/full-react-imperative/app/pages/login/LoginPage.tsx +65 -0
- package/full-react-imperative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +64 -0
- package/full-react-imperative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +56 -0
- package/full-react-imperative/app/pages/register/RegisterPage.tsx +71 -0
- package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.css +64 -0
- package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.tsx +104 -0
- package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.css +0 -0
- package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.tsx +43 -0
- package/full-react-imperative/app/pages/users/UserPage/UserPage.css +31 -0
- package/full-react-imperative/app/pages/users/UserPage/UserPage.tsx +59 -0
- package/full-react-imperative/app/pages/utils.ts +67 -0
- package/full-react-imperative/app/providers/AppServiceProvider.ts +40 -0
- package/full-react-imperative/app/services/CommentService.ts +53 -0
- package/full-react-imperative/app/services/PostService.ts +102 -0
- package/full-react-imperative/app/services/SecurityService.ts +72 -0
- package/full-react-imperative/app/services/TokenService.ts +108 -0
- package/full-react-imperative/app/services/UserService.ts +115 -0
- package/full-react-imperative/app/services/contracts/ICommentService.ts +30 -0
- package/full-react-imperative/app/services/contracts/IPostService.ts +65 -0
- package/full-react-imperative/app/services/contracts/ISecurityService.ts +39 -0
- package/full-react-imperative/app/services/contracts/ITokenService.ts +44 -0
- package/full-react-imperative/app/services/contracts/IUserService.ts +70 -0
- package/full-react-imperative/app/utils.ts +31 -0
- package/full-react-imperative/assets/css/index.css +301 -0
- package/full-react-imperative/assets/img/logo.png +0 -0
- package/full-react-imperative/package.json +48 -0
- package/full-react-imperative/public/logo.png +0 -0
- package/full-react-imperative/public/vite.svg +1 -0
- package/full-react-imperative/stone.config.mjs +12 -0
- package/full-react-imperative/tsconfig.json +29 -0
- package/full-react-imperative/vitest.config.ts +24 -0
- package/full-service-declarative/.env.example +2 -0
- package/full-service-declarative/LICENSE +21 -0
- package/full-service-declarative/README.md +65 -0
- package/full-service-declarative/app/Application.ts +327 -0
- package/full-service-declarative/app/commands/ListSessionsCommand.ts +70 -0
- package/full-service-declarative/app/commands/ListUsersCommand.ts +56 -0
- package/full-service-declarative/app/configurations/AppConfiguration.ts +52 -0
- package/full-service-declarative/app/configurations/UserLiveConfiguration.ts +28 -0
- package/full-service-declarative/app/database/DatabaseClient.ts +43 -0
- package/full-service-declarative/app/database/schema.ts +43 -0
- package/full-service-declarative/app/error-handlers/SecurityErrorHandler.ts +61 -0
- package/full-service-declarative/app/errors/CredentialsError.ts +12 -0
- package/full-service-declarative/app/events/UserEvent.ts +17 -0
- package/full-service-declarative/app/handlers/CommentEventHandler.ts +103 -0
- package/full-service-declarative/app/handlers/PostEventHandler.ts +104 -0
- package/full-service-declarative/app/handlers/SecurityEventHandler.ts +108 -0
- package/full-service-declarative/app/handlers/UserEventHandler.ts +159 -0
- package/full-service-declarative/app/listeners/UserEventListener.ts +35 -0
- package/full-service-declarative/app/middleware/AuthMiddleware.ts +54 -0
- package/full-service-declarative/app/models/Comment.ts +38 -0
- package/full-service-declarative/app/models/Post.ts +50 -0
- package/full-service-declarative/app/models/Session.ts +14 -0
- package/full-service-declarative/app/models/User.ts +77 -0
- package/full-service-declarative/app/providers/DrizzleServiceProvider.ts +59 -0
- package/full-service-declarative/app/repositories/CommentRepository.ts +155 -0
- package/full-service-declarative/app/repositories/PostRepository.ts +138 -0
- package/full-service-declarative/app/repositories/SessionRepository.ts +123 -0
- package/full-service-declarative/app/repositories/UserRepository.ts +99 -0
- package/full-service-declarative/app/services/CommentService.ts +112 -0
- package/full-service-declarative/app/services/PostService.ts +100 -0
- package/full-service-declarative/app/services/SecurityService.ts +232 -0
- package/full-service-declarative/app/services/SessionService.ts +130 -0
- package/full-service-declarative/app/services/UserService.ts +110 -0
- package/full-service-declarative/app/subscribers/UserEventSubscriber.ts +38 -0
- package/full-service-declarative/drizzle.config.ts +13 -0
- package/full-service-declarative/package.json +48 -0
- package/full-service-declarative/stone.config.mjs +12 -0
- package/full-service-declarative/tsconfig.json +25 -0
- package/full-service-declarative/vitest.config.ts +24 -0
- package/full-service-imperative/.env.example +2 -0
- package/full-service-imperative/LICENSE +21 -0
- package/full-service-imperative/README.md +65 -0
- package/full-service-imperative/app/Application.ts +317 -0
- package/full-service-imperative/app/commands/ListSessionsCommand.ts +54 -0
- package/full-service-imperative/app/commands/ListUsersCommand.ts +42 -0
- package/full-service-imperative/app/configurations/AppConfiguration.ts +44 -0
- package/full-service-imperative/app/configurations/UserLiveConfiguration.ts +26 -0
- package/full-service-imperative/app/database/DatabaseClient.ts +39 -0
- package/full-service-imperative/app/database/schema.ts +43 -0
- package/full-service-imperative/app/error-handlers/SecurityErrorHandler.ts +58 -0
- package/full-service-imperative/app/errors/CredentialsError.ts +12 -0
- package/full-service-imperative/app/events/UserEvent.ts +17 -0
- package/full-service-imperative/app/handlers/CommentEventHandler.ts +99 -0
- package/full-service-imperative/app/handlers/PostEventHandler.ts +99 -0
- package/full-service-imperative/app/handlers/SecurityEventHandler.ts +83 -0
- package/full-service-imperative/app/handlers/UserEventHandler.ts +132 -0
- package/full-service-imperative/app/listeners/UserEventListener.ts +23 -0
- package/full-service-imperative/app/middleware/AuthMiddleware.ts +44 -0
- package/full-service-imperative/app/models/Comment.ts +38 -0
- package/full-service-imperative/app/models/Post.ts +50 -0
- package/full-service-imperative/app/models/Session.ts +14 -0
- package/full-service-imperative/app/models/User.ts +77 -0
- package/full-service-imperative/app/providers/DrizzleServiceProvider.ts +56 -0
- package/full-service-imperative/app/repositories/CommentRepository.ts +148 -0
- package/full-service-imperative/app/repositories/PostRepository.ts +130 -0
- package/full-service-imperative/app/repositories/SessionRepository.ts +115 -0
- package/full-service-imperative/app/repositories/UserRepository.ts +91 -0
- package/full-service-imperative/app/repositories/contracts/ICommentRepository.ts +72 -0
- package/full-service-imperative/app/repositories/contracts/IPostRepository.ts +63 -0
- package/full-service-imperative/app/repositories/contracts/ISessionRepository.ts +65 -0
- package/full-service-imperative/app/repositories/contracts/IUserRepository.ts +55 -0
- package/full-service-imperative/app/services/CommentService.ts +109 -0
- package/full-service-imperative/app/services/PostService.ts +97 -0
- package/full-service-imperative/app/services/SecurityService.ts +224 -0
- package/full-service-imperative/app/services/SessionService.ts +124 -0
- package/full-service-imperative/app/services/UserService.ts +105 -0
- package/full-service-imperative/app/services/contracts/ICommentService.ts +62 -0
- package/full-service-imperative/app/services/contracts/IPostService.ts +53 -0
- package/full-service-imperative/app/services/contracts/ISecurityService.ts +97 -0
- package/full-service-imperative/app/services/contracts/ISessionService.ts +73 -0
- package/full-service-imperative/app/services/contracts/IUserService.ts +57 -0
- package/full-service-imperative/app/subscribers/UserEventSubscriber.ts +28 -0
- package/full-service-imperative/drizzle.config.ts +13 -0
- package/full-service-imperative/package.json +48 -0
- package/full-service-imperative/stone.config.mjs +12 -0
- package/full-service-imperative/tsconfig.json +25 -0
- package/full-service-imperative/vitest.config.ts +24 -0
- package/package.json +225 -0
- package/standard-react-declarative/LICENSE +21 -0
- package/standard-react-declarative/README.md +39 -0
- package/standard-react-declarative/app/Application.ts +45 -0
- package/standard-react-declarative/app/pages/welcome/WelcomePage.tsx +57 -0
- package/standard-react-declarative/app/services/WelcomeService.ts +38 -0
- package/standard-react-declarative/assets/css/index.css +26 -0
- package/standard-react-declarative/package.json +42 -0
- package/standard-react-declarative/tsconfig.json +33 -0
- package/standard-react-declarative/vitest.config.ts +24 -0
- package/standard-react-imperative/LICENSE +21 -0
- package/standard-react-imperative/README.md +39 -0
- package/standard-react-imperative/app/Application.ts +41 -0
- package/standard-react-imperative/app/pages/welcome/WelcomePage.tsx +50 -0
- package/standard-react-imperative/app/services/WelcomeService.ts +38 -0
- package/standard-react-imperative/assets/css/index.css +26 -0
- package/standard-react-imperative/package.json +42 -0
- package/standard-react-imperative/tsconfig.json +33 -0
- package/standard-react-imperative/vitest.config.ts +24 -0
- package/standard-service-declarative/LICENSE +21 -0
- package/standard-service-declarative/README.md +39 -0
- package/standard-service-declarative/app/Application.ts +39 -0
- package/standard-service-declarative/app/handlers/WelcomeEventHandler.ts +45 -0
- package/standard-service-declarative/app/services/WelcomeService.ts +38 -0
- package/standard-service-declarative/package.json +36 -0
- package/standard-service-declarative/tsconfig.json +25 -0
- package/standard-service-declarative/vitest.config.ts +24 -0
- package/standard-service-imperative/LICENSE +21 -0
- package/standard-service-imperative/README.md +39 -0
- package/standard-service-imperative/app/Application.ts +11 -0
- package/standard-service-imperative/app/handlers/welcomeEventHandler.ts +31 -0
- package/standard-service-imperative/app/services/welcomeService.ts +38 -0
- package/standard-service-imperative/package.json +35 -0
- package/standard-service-imperative/tsconfig.json +25 -0
- package/standard-service-imperative/vitest.config.ts +24 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Stone } from '@stone-js/core'
|
|
2
|
+
import { AxiosClient } from './AxiosClient'
|
|
3
|
+
import { Post, PostInput } from '../models/Post'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Post Client Options
|
|
7
|
+
*/
|
|
8
|
+
export interface PostClientOptions {
|
|
9
|
+
httpClient: AxiosClient
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Post Client
|
|
14
|
+
*/
|
|
15
|
+
@Stone({ alias: 'postClient' })
|
|
16
|
+
export class PostClient {
|
|
17
|
+
private readonly path: string
|
|
18
|
+
private readonly client: AxiosClient
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a new Post Client
|
|
22
|
+
*
|
|
23
|
+
* @param options - The options to create the Post Client.
|
|
24
|
+
*/
|
|
25
|
+
constructor ({ httpClient }: PostClientOptions) {
|
|
26
|
+
this.client = httpClient
|
|
27
|
+
this.path = '/posts'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* List posts
|
|
32
|
+
*
|
|
33
|
+
* @param limit - The limit of posts to list
|
|
34
|
+
* @returns The list of posts
|
|
35
|
+
*/
|
|
36
|
+
async list (limit: number = 10): Promise<Post[]> {
|
|
37
|
+
return await this.client.get<Post[]>(`${this.path}?limit=${limit}`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* List posts by author
|
|
42
|
+
*
|
|
43
|
+
* @param id - The id of the author to list posts
|
|
44
|
+
* @param limit - The limit of posts to list
|
|
45
|
+
* @returns The list of posts
|
|
46
|
+
*/
|
|
47
|
+
async listByAuthor (id: number, limit: number = 10): Promise<Post[]> {
|
|
48
|
+
return await this.client.get<Post[]>(`${this.path}/authors/${id}?limit=${limit}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Find an post
|
|
53
|
+
*
|
|
54
|
+
* @param id - The id of the post to find
|
|
55
|
+
* @returns The found post
|
|
56
|
+
*/
|
|
57
|
+
async find (id: number): Promise<Post> {
|
|
58
|
+
return await this.client.get<Post>(`${this.path}/${id}`)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create an post
|
|
63
|
+
*
|
|
64
|
+
* @param post - The post to create
|
|
65
|
+
* @returns The created post
|
|
66
|
+
*/
|
|
67
|
+
async create (post: PostInput): Promise<Post> {
|
|
68
|
+
return await this.client.post(this.path, post)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Update an post
|
|
73
|
+
*
|
|
74
|
+
* @param id - The id of the post to update
|
|
75
|
+
* @param post - The post to update
|
|
76
|
+
* @returns The updated post
|
|
77
|
+
*/
|
|
78
|
+
async update (id: number, post: PostInput): Promise<Post> {
|
|
79
|
+
return await this.client.patch(`${this.path}/${id}`, post)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Delete an post
|
|
84
|
+
*
|
|
85
|
+
* @param id - The id of the post to delete
|
|
86
|
+
*/
|
|
87
|
+
async delete (id: number): Promise<unknown> {
|
|
88
|
+
return await this.client.delete(`${this.path}/${id}`)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
import { Axios } from 'axios'
|
|
3
|
+
import { Stone } from '@stone-js/core'
|
|
4
|
+
import { AxiosClient } from './AxiosClient'
|
|
5
|
+
import { UserChangePassword, UserLogin, UserRegister, UserToken } from '../models/User'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Security Client Options
|
|
9
|
+
*/
|
|
10
|
+
export interface SecurityClientOptions {
|
|
11
|
+
axios: Axios
|
|
12
|
+
httpClient: AxiosClient
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Security Client
|
|
17
|
+
*/
|
|
18
|
+
@Stone({ alias: 'securityClient' })
|
|
19
|
+
export class SecurityClient {
|
|
20
|
+
private readonly axios: Axios
|
|
21
|
+
private readonly client: AxiosClient
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a new Security Client
|
|
25
|
+
*
|
|
26
|
+
* @param options - The options to create the Security Client.
|
|
27
|
+
*/
|
|
28
|
+
constructor ({ axios, httpClient }: SecurityClientOptions) {
|
|
29
|
+
this.axios = axios
|
|
30
|
+
this.client = httpClient
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Login a user
|
|
35
|
+
*
|
|
36
|
+
* @param user - The user to login
|
|
37
|
+
*/
|
|
38
|
+
async login (user: UserLogin): Promise<UserToken> {
|
|
39
|
+
return (await this.axios.post<UserToken>('/login', user)).data
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Logout a user
|
|
44
|
+
*/
|
|
45
|
+
async logout (): Promise<void> {
|
|
46
|
+
await this.client.post<UserToken>('/logout')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Register a user
|
|
51
|
+
*
|
|
52
|
+
* @param user - The user to register
|
|
53
|
+
*/
|
|
54
|
+
async register (user: UserRegister): Promise<void> {
|
|
55
|
+
await this.axios.post('/register', user)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Change the user password
|
|
60
|
+
*
|
|
61
|
+
* @param password - The password to change
|
|
62
|
+
*/
|
|
63
|
+
async changePassword (password: UserChangePassword): Promise<void> {
|
|
64
|
+
await this.client.patch('/change-password', password)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Stone } from '@stone-js/core'
|
|
2
|
+
import { AxiosClient } from './AxiosClient'
|
|
3
|
+
import { User, UserInput } from '../models/User'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* User Client Options
|
|
7
|
+
*/
|
|
8
|
+
export interface UserClientOptions {
|
|
9
|
+
httpClient: AxiosClient
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* User Client
|
|
14
|
+
*/
|
|
15
|
+
@Stone({ alias: 'userClient' })
|
|
16
|
+
export class UserClient {
|
|
17
|
+
private readonly path: string
|
|
18
|
+
private readonly client: AxiosClient
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a new User Client
|
|
22
|
+
*
|
|
23
|
+
* @param options - The options to create the User Client.
|
|
24
|
+
*/
|
|
25
|
+
constructor ({ httpClient }: UserClientOptions) {
|
|
26
|
+
this.path = '/users'
|
|
27
|
+
this.client = httpClient
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* List users
|
|
32
|
+
*
|
|
33
|
+
* @param limit - The limit of users to list
|
|
34
|
+
* @returns The list of users
|
|
35
|
+
*/
|
|
36
|
+
async list (limit: number = 10): Promise<User[]> {
|
|
37
|
+
return await this.client.get<User[]>(`${this.path}?limit=${limit}`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the current user
|
|
42
|
+
*
|
|
43
|
+
* @returns The current user
|
|
44
|
+
*/
|
|
45
|
+
async currentUser (): Promise<User> {
|
|
46
|
+
return await this.client.get<User>(`${this.path}/me`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Find a user
|
|
51
|
+
*
|
|
52
|
+
* @param id - The id of the user to find
|
|
53
|
+
* @returns The found user
|
|
54
|
+
*/
|
|
55
|
+
async find (id: number): Promise<User> {
|
|
56
|
+
return await this.client.get<User>(`${this.path}/${id}`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a user
|
|
61
|
+
*
|
|
62
|
+
* @param user - The user to create
|
|
63
|
+
*/
|
|
64
|
+
async create (user: UserInput): Promise<User> {
|
|
65
|
+
return await this.client.post(this.path, user)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Update the current user
|
|
70
|
+
*
|
|
71
|
+
* @param user - The current user
|
|
72
|
+
* @returns The current user
|
|
73
|
+
*/
|
|
74
|
+
async updateCurrent (user: UserInput): Promise<User> {
|
|
75
|
+
return await this.client.patch(`${this.path}/me`, user)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Update a user
|
|
80
|
+
*
|
|
81
|
+
* @param id - The id of the user to update
|
|
82
|
+
* @param user - The user to update
|
|
83
|
+
* @returns The updated user
|
|
84
|
+
*/
|
|
85
|
+
async update (id: number, user: UserInput): Promise<User> {
|
|
86
|
+
return await this.client.patch(`${this.path}/${id}`, user)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Delete a user
|
|
91
|
+
*
|
|
92
|
+
* @param id - The id of the user to delete
|
|
93
|
+
*/
|
|
94
|
+
async delete (id: number): Promise<unknown> {
|
|
95
|
+
return await this.client.delete(`${this.path}/${id}`)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { FC, useRef } from 'react'
|
|
2
|
+
import { UserChangePassword } from '../../models/User'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Change Password Form Options
|
|
6
|
+
*/
|
|
7
|
+
export interface ChangePasswordFormOptions {
|
|
8
|
+
onSubmit: (user: UserChangePassword) => Promise<void>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Change Password Form component.
|
|
13
|
+
*
|
|
14
|
+
* @param options - The options to create the Change Password Form component.
|
|
15
|
+
*/
|
|
16
|
+
export const ChangePasswordForm: FC<ChangePasswordFormOptions> = ({ onSubmit }) => {
|
|
17
|
+
// Create a reference to the user
|
|
18
|
+
const userRef = useRef<UserChangePassword>({
|
|
19
|
+
password: '',
|
|
20
|
+
newPassword: '',
|
|
21
|
+
confirmPassword: ''
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Handle the form submit
|
|
25
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
26
|
+
event.preventDefault()
|
|
27
|
+
void onSubmit(userRef.current).catch(() => {})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Handle the field change
|
|
31
|
+
const onChange = (field: keyof UserChangePassword) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
32
|
+
userRef.current[field] = event.target.value
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Render the component
|
|
36
|
+
return (
|
|
37
|
+
<form onSubmit={handleSubmit}>
|
|
38
|
+
<label htmlFor='password'>Current Password:</label>
|
|
39
|
+
<input id='password' type='password' onChange={onChange('password')} defaultValue={userRef.current.password} />
|
|
40
|
+
|
|
41
|
+
<label htmlFor='newPassword'>New Password:</label>
|
|
42
|
+
<input id='newPassword' type='password' onChange={onChange('newPassword')} defaultValue={userRef.current.newPassword} />
|
|
43
|
+
|
|
44
|
+
<label htmlFor='confirmPassword'>Confirm password:</label>
|
|
45
|
+
<input id='confirmPassword' type='password' onChange={onChange('confirmPassword')} defaultValue={userRef.current.confirmPassword} />
|
|
46
|
+
|
|
47
|
+
<button type='submit'>ChangePassword</button>
|
|
48
|
+
</form>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FC, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comment Form Props
|
|
5
|
+
*/
|
|
6
|
+
export interface CommentFormOptions {
|
|
7
|
+
onSubmit: (content: string) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Comment Form component.
|
|
12
|
+
*/
|
|
13
|
+
export const CommentForm: FC<CommentFormOptions> = ({ onSubmit }) => {
|
|
14
|
+
const contentRef = useRef<HTMLInputElement>(null)
|
|
15
|
+
|
|
16
|
+
// Handle the form submit
|
|
17
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
18
|
+
event.preventDefault()
|
|
19
|
+
if (contentRef.current === null) return
|
|
20
|
+
|
|
21
|
+
const content = contentRef.current.value.trim()
|
|
22
|
+
if (content.length === 0) return // Prevent empty submissions
|
|
23
|
+
|
|
24
|
+
contentRef.current.value = '' // Clear input field
|
|
25
|
+
onSubmit(content)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Render the component
|
|
29
|
+
return (
|
|
30
|
+
<form onSubmit={handleSubmit}>
|
|
31
|
+
<p>
|
|
32
|
+
<input ref={contentRef} type='text' placeholder='Write a comment...' />
|
|
33
|
+
<button type='submit'>Add Comment</button>
|
|
34
|
+
</p>
|
|
35
|
+
</form>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FC, useState } from 'react'
|
|
2
|
+
import { formatDateTime } from '../../utils'
|
|
3
|
+
import { CommentView } from '../../models/Comment'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Comment Item Props
|
|
7
|
+
*/
|
|
8
|
+
export interface CommentItemProps {
|
|
9
|
+
commentView: CommentView
|
|
10
|
+
onRetry: (commentView: CommentView) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Comment Item component.
|
|
15
|
+
*/
|
|
16
|
+
export const CommentItem: FC<CommentItemProps> = ({ commentView, onRetry }) => {
|
|
17
|
+
const [comment, setComment] = useState<CommentView>(commentView)
|
|
18
|
+
|
|
19
|
+
// Handle the retry
|
|
20
|
+
const handleOnClick = (): void => {
|
|
21
|
+
setComment({ ...comment, status: 'saving' })
|
|
22
|
+
onRetry(comment)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Render the component
|
|
26
|
+
return (
|
|
27
|
+
<div>
|
|
28
|
+
<p>{comment.content}</p>
|
|
29
|
+
<p>
|
|
30
|
+
<span>{comment.author.name}</span>
|
|
31
|
+
<span>{formatDateTime(comment.createdAt)}</span>
|
|
32
|
+
</p>
|
|
33
|
+
{comment.status === 'saving' && <p>Saving...</p>}
|
|
34
|
+
{comment.status === 'error' && (
|
|
35
|
+
<p>
|
|
36
|
+
<span>Error adding the comment!</span>
|
|
37
|
+
<button onClick={handleOnClick}>Retry</button>
|
|
38
|
+
</p>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { User } from '../../models/User'
|
|
2
|
+
import { Post } from '../../models/Post'
|
|
3
|
+
import { FC, useEffect, useState } from 'react'
|
|
4
|
+
import { CommentItem } from '../CommentItem/CommentItem'
|
|
5
|
+
import { CommentForm } from '../CommentForm/CommentForm'
|
|
6
|
+
import { CommentService } from '../../services/CommentService'
|
|
7
|
+
import { CommentInput, CommentView } from '../../models/Comment'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Comment Widget Options
|
|
11
|
+
*/
|
|
12
|
+
export interface CommentWidgetOptions {
|
|
13
|
+
post: Post
|
|
14
|
+
user: User
|
|
15
|
+
commentService: CommentService
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Comment Items component.
|
|
20
|
+
*/
|
|
21
|
+
export const CommentWidget: FC<CommentWidgetOptions> = ({ post, user, commentService }) => {
|
|
22
|
+
const [comments, setComments] = useState<CommentView[]>([])
|
|
23
|
+
const [fetchingStatus, setFetchingStatus] = useState<'idle' | 'loading' | 'error'>('idle')
|
|
24
|
+
|
|
25
|
+
// Fetch comments
|
|
26
|
+
const fetchComments = (): void => {
|
|
27
|
+
setFetchingStatus('loading')
|
|
28
|
+
commentService
|
|
29
|
+
.list(post.id)
|
|
30
|
+
.then(comments => {
|
|
31
|
+
setComments(comments)
|
|
32
|
+
setFetchingStatus('idle')
|
|
33
|
+
})
|
|
34
|
+
.catch(() => {
|
|
35
|
+
setFetchingStatus('error')
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Save comment
|
|
40
|
+
const saveComment = (commentInput: CommentInput): void => {
|
|
41
|
+
commentService
|
|
42
|
+
.create(post.id, commentInput)
|
|
43
|
+
.then(() => fetchComments())
|
|
44
|
+
.catch(() => {
|
|
45
|
+
setComments(comments.map(comment => ({
|
|
46
|
+
...comment,
|
|
47
|
+
status: comment.id === commentInput.id ? 'error' : comment.status
|
|
48
|
+
})))
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle save
|
|
53
|
+
const handleOnSubmit = (content: string): void => {
|
|
54
|
+
const id = Math.random()
|
|
55
|
+
const commentInput: CommentInput = {
|
|
56
|
+
id,
|
|
57
|
+
content,
|
|
58
|
+
postId: post.id
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const commentView: CommentView = {
|
|
62
|
+
...commentInput,
|
|
63
|
+
author: user,
|
|
64
|
+
status: 'saving',
|
|
65
|
+
createdAt: Date.now()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setComments([...comments, commentView])
|
|
69
|
+
|
|
70
|
+
saveComment(commentInput)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Fetch comments on mount
|
|
74
|
+
useEffect(() => { fetchComments() }, [post.id])
|
|
75
|
+
|
|
76
|
+
// Render
|
|
77
|
+
if (comments.length === 0 && fetchingStatus === 'loading') {
|
|
78
|
+
return <p>Loading comments...</p>
|
|
79
|
+
} else if (comments.length === 0 && fetchingStatus === 'error') {
|
|
80
|
+
return <p>Error fetching comments</p>
|
|
81
|
+
} else if (comments.length === 0 && fetchingStatus === 'idle') {
|
|
82
|
+
return <p>No comments yet</p>
|
|
83
|
+
} else {
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<CommentForm onSubmit={handleOnSubmit} />
|
|
87
|
+
<div>
|
|
88
|
+
{comments.map((comment) => (
|
|
89
|
+
<CommentItem key={comment.id} commentView={comment} onRetry={saveComment} />
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import './LoginForm.css'
|
|
2
|
+
import { FC, useRef } from 'react'
|
|
3
|
+
import { UserLogin } from '../../models/User'
|
|
4
|
+
import { StoneLink } from '@stone-js/use-react'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Login Form Options
|
|
8
|
+
*/
|
|
9
|
+
export interface LoginFormOptions {
|
|
10
|
+
error: boolean
|
|
11
|
+
onSubmit: (user: UserLogin) => Promise<void>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Login Form component.
|
|
16
|
+
*
|
|
17
|
+
* @param options - The options to create the Login Form component.
|
|
18
|
+
*/
|
|
19
|
+
export const LoginForm: FC<LoginFormOptions> = ({ error, onSubmit }) => {
|
|
20
|
+
// Create a reference to the login
|
|
21
|
+
const loginRef = useRef<UserLogin>({
|
|
22
|
+
email: '',
|
|
23
|
+
password: ''
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Handle the form submit
|
|
27
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
28
|
+
event.preventDefault()
|
|
29
|
+
void onSubmit(loginRef.current).catch(() => {})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Handle the field change
|
|
33
|
+
const onChange = (field: keyof UserLogin) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
34
|
+
loginRef.current[field] = event.target.value
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Render the component
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<form onSubmit={handleSubmit} className='panel'>
|
|
41
|
+
{error && <p className='alert alert-danger alert-small'>Invalid email or password</p>}
|
|
42
|
+
|
|
43
|
+
<div>
|
|
44
|
+
<label htmlFor='email' className='label'>Email:</label>
|
|
45
|
+
<input
|
|
46
|
+
id='email'
|
|
47
|
+
type='email'
|
|
48
|
+
className='input'
|
|
49
|
+
placeholder='Enter your email'
|
|
50
|
+
onChange={onChange('email')} defaultValue={loginRef.current.email}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div className='mt-8'>
|
|
55
|
+
<label htmlFor='password' className='label'>Password:</label>
|
|
56
|
+
<input
|
|
57
|
+
id='password'
|
|
58
|
+
type='password'
|
|
59
|
+
className='input'
|
|
60
|
+
placeholder='Enter your password'
|
|
61
|
+
onChange={onChange('password')} defaultValue={loginRef.current.password}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
<button type='submit' className='button button-secondary button-full mt-24'>Login</button>
|
|
65
|
+
</form>
|
|
66
|
+
<p className='mt-24 text-center'>
|
|
67
|
+
<StoneLink to='/register' className='button button-primary'>Register</StoneLink>
|
|
68
|
+
</p>
|
|
69
|
+
</>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FC } from 'react'
|
|
2
|
+
import { Post } from '../../models/Post'
|
|
3
|
+
import { User } from '../../models/User'
|
|
4
|
+
import { formatDateTime } from '../../utils'
|
|
5
|
+
import { StoneLink } from '@stone-js/use-react'
|
|
6
|
+
import { CommentWidget } from '../CommentWidget/CommentWidget'
|
|
7
|
+
import { CommentService } from '../../services/CommentService'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Post details Options
|
|
11
|
+
*/
|
|
12
|
+
export interface PostDetailsOptions {
|
|
13
|
+
post: Post
|
|
14
|
+
user: User
|
|
15
|
+
commentService: CommentService
|
|
16
|
+
onDelete: (post: Post) => Promise<void>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Post details component.
|
|
21
|
+
*
|
|
22
|
+
* @param options - The options to create the Post details component.
|
|
23
|
+
*/
|
|
24
|
+
export const PostDetails: FC<PostDetailsOptions> = ({ user, onDelete, post, commentService }) => {
|
|
25
|
+
const deletePost = (): void => {
|
|
26
|
+
void onDelete(post).catch(() => {})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<article>
|
|
31
|
+
<h1>{post.title}</h1>
|
|
32
|
+
<p>
|
|
33
|
+
<span>{post.author.name}</span>
|
|
34
|
+
<span>{formatDateTime(post.createdAt)}</span>
|
|
35
|
+
</p>
|
|
36
|
+
<p>{post.content}</p>
|
|
37
|
+
<p>
|
|
38
|
+
<StoneLink to={`/posts/${post.id}/edit`}>Edit</StoneLink>
|
|
39
|
+
<button onClick={deletePost}>Delete</button>
|
|
40
|
+
</p>
|
|
41
|
+
<CommentWidget user={user} commentService={commentService} post={post} />
|
|
42
|
+
</article>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { FC, useRef } from 'react'
|
|
2
|
+
import { PostInput } from '../../models/Post'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Post Form Options
|
|
6
|
+
*/
|
|
7
|
+
export interface PostFormOptions {
|
|
8
|
+
post?: PostInput
|
|
9
|
+
onSubmit: (post: PostInput) => Promise<void>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Post Form component.
|
|
14
|
+
*
|
|
15
|
+
* @param options - The options to create the Post Form component.
|
|
16
|
+
*/
|
|
17
|
+
export const PostForm: FC<PostFormOptions> = ({ post, onSubmit }) => {
|
|
18
|
+
// Create a reference to the post
|
|
19
|
+
const postRef = useRef<PostInput>({
|
|
20
|
+
title: post?.title ?? '',
|
|
21
|
+
content: post?.content ?? ''
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Handle the form submit
|
|
25
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
26
|
+
event.preventDefault()
|
|
27
|
+
void onSubmit(postRef.current).catch(() => {})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Handle the field change
|
|
31
|
+
const onChange = (field: keyof PostInput) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
32
|
+
postRef.current[field] = event.target.value
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Render the component
|
|
36
|
+
return (
|
|
37
|
+
<form onSubmit={handleSubmit}>
|
|
38
|
+
<label htmlFor='title'>Title:</label>
|
|
39
|
+
<input id='title' type='text' onChange={onChange('title')} defaultValue={postRef.current.title} />
|
|
40
|
+
|
|
41
|
+
<label htmlFor='content'>Content:</label>
|
|
42
|
+
<input id='content' type='text' onChange={onChange('content')} defaultValue={postRef.current.content} />
|
|
43
|
+
|
|
44
|
+
<button type='submit'>Publish</button>
|
|
45
|
+
</form>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FC } from 'react'
|
|
2
|
+
import { Post } from '../../models/Post'
|
|
3
|
+
import { StoneLink } from '@stone-js/use-react'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Post Item Options
|
|
7
|
+
*/
|
|
8
|
+
export interface PostItemOptions {
|
|
9
|
+
post: Post
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Post Item component.
|
|
14
|
+
*
|
|
15
|
+
* @param options - The options to create the Post Item component.
|
|
16
|
+
*/
|
|
17
|
+
export const PostItem: FC<PostItemOptions> = ({ post }) => {
|
|
18
|
+
return (
|
|
19
|
+
<article>
|
|
20
|
+
<h3>
|
|
21
|
+
<StoneLink to={`/posts/${post.id}`}>{post.title}</StoneLink>
|
|
22
|
+
</h3>
|
|
23
|
+
<p>
|
|
24
|
+
<span>{post.author.name}</span>
|
|
25
|
+
<span>{new Date(post.createdAt).toISOString()}</span>
|
|
26
|
+
</p>
|
|
27
|
+
<p>{post.content.substring(0, 32)}</p>
|
|
28
|
+
<p>
|
|
29
|
+
<StoneLink to={`/posts/${post.id}`}>Show</StoneLink>
|
|
30
|
+
<StoneLink to={`/posts/${post.id}/edit`}>Edit</StoneLink>
|
|
31
|
+
</p>
|
|
32
|
+
</article>
|
|
33
|
+
)
|
|
34
|
+
}
|