@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.
Files changed (352) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/basic-react-declarative/LICENSE +21 -0
  4. package/basic-react-declarative/README.md +39 -0
  5. package/basic-react-declarative/app/Application.tsx +89 -0
  6. package/basic-react-declarative/assets/css/index.css +26 -0
  7. package/basic-react-declarative/package.json +39 -0
  8. package/basic-react-declarative/public/logo.png +0 -0
  9. package/basic-react-declarative/tests/Application.spec.ts +96 -0
  10. package/basic-react-declarative/tests/__snapshots__/Application.spec.ts.snap +3 -0
  11. package/basic-react-declarative/tsconfig.json +33 -0
  12. package/basic-react-declarative/vitest.config.ts +24 -0
  13. package/basic-react-imperative/LICENSE +21 -0
  14. package/basic-react-imperative/README.md +39 -0
  15. package/basic-react-imperative/app/Application.tsx +89 -0
  16. package/basic-react-imperative/assets/css/index.css +26 -0
  17. package/basic-react-imperative/package.json +39 -0
  18. package/basic-react-imperative/public/logo.png +0 -0
  19. package/basic-react-imperative/tests/Application.spec.ts +80 -0
  20. package/basic-react-imperative/tests/__snapshots__/Application.spec.ts.snap +3 -0
  21. package/basic-react-imperative/tsconfig.json +33 -0
  22. package/basic-react-imperative/vitest.config.ts +24 -0
  23. package/basic-service-declarative/LICENSE +21 -0
  24. package/basic-service-declarative/README.md +39 -0
  25. package/basic-service-declarative/app/Application.ts +56 -0
  26. package/basic-service-declarative/package.json +34 -0
  27. package/basic-service-declarative/tests/Application.spec.ts +60 -0
  28. package/basic-service-declarative/tsconfig.json +25 -0
  29. package/basic-service-declarative/vitest.config.ts +24 -0
  30. package/basic-service-imperative/LICENSE +21 -0
  31. package/basic-service-imperative/README.md +39 -0
  32. package/basic-service-imperative/app/Application.ts +60 -0
  33. package/basic-service-imperative/package.json +34 -0
  34. package/basic-service-imperative/tests/Application.spec.ts +52 -0
  35. package/basic-service-imperative/tsconfig.json +25 -0
  36. package/basic-service-imperative/vitest.config.ts +24 -0
  37. package/continuum-showcase/README.md +44 -0
  38. package/continuum-showcase/app/env.d.ts +34 -0
  39. package/continuum-showcase/app/layouts/MainLayout.tsx +20 -0
  40. package/continuum-showcase/app/pages/BlogPostPage.tsx +62 -0
  41. package/continuum-showcase/app/pages/HomePage.tsx +58 -0
  42. package/continuum-showcase/package.json +25 -0
  43. package/continuum-showcase/stone.config.mjs +20 -0
  44. package/full-react-declarative/.env.example +1 -0
  45. package/full-react-declarative/.env.public.example +1 -0
  46. package/full-react-declarative/LICENSE +21 -0
  47. package/full-react-declarative/README.md +39 -0
  48. package/full-react-declarative/app/Application.ts +85 -0
  49. package/full-react-declarative/app/clients/AxiosClient.ts +136 -0
  50. package/full-react-declarative/app/clients/CommentClient.ts +61 -0
  51. package/full-react-declarative/app/clients/PostClient.ts +90 -0
  52. package/full-react-declarative/app/clients/SecurityClient.ts +66 -0
  53. package/full-react-declarative/app/clients/UserClient.ts +97 -0
  54. package/full-react-declarative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
  55. package/full-react-declarative/app/components/CommentForm/CommentForm.tsx +37 -0
  56. package/full-react-declarative/app/components/CommentItem/CommentItem.tsx +42 -0
  57. package/full-react-declarative/app/components/CommentWidget/CommentWidget.tsx +95 -0
  58. package/full-react-declarative/app/components/LoginForm/LoginForm.css +0 -0
  59. package/full-react-declarative/app/components/LoginForm/LoginForm.tsx +71 -0
  60. package/full-react-declarative/app/components/PostDetails/PostDetails.tsx +44 -0
  61. package/full-react-declarative/app/components/PostForm/PostForm.css +0 -0
  62. package/full-react-declarative/app/components/PostForm/PostForm.tsx +47 -0
  63. package/full-react-declarative/app/components/PostItem/PostItem.css +0 -0
  64. package/full-react-declarative/app/components/PostItem/PostItem.tsx +34 -0
  65. package/full-react-declarative/app/components/RegisterForm/RegisterForm.tsx +110 -0
  66. package/full-react-declarative/app/components/UserForm/UserForm.tsx +47 -0
  67. package/full-react-declarative/app/configurations/AppConfiguration.ts +17 -0
  68. package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
  69. package/full-react-declarative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +52 -0
  70. package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
  71. package/full-react-declarative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +53 -0
  72. package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
  73. package/full-react-declarative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +54 -0
  74. package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
  75. package/full-react-declarative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +53 -0
  76. package/full-react-declarative/app/errors/ForbiddenError.ts +11 -0
  77. package/full-react-declarative/app/errors/PostNotFoundError.ts +11 -0
  78. package/full-react-declarative/app/errors/UnauthorizedError.ts +11 -0
  79. package/full-react-declarative/app/errors/UserNotFoundError.ts +11 -0
  80. package/full-react-declarative/app/events/UserEvent.ts +18 -0
  81. package/full-react-declarative/app/layout/AppLayout/AppLayout.css +20 -0
  82. package/full-react-declarative/app/layout/AppLayout/AppLayout.tsx +101 -0
  83. package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
  84. package/full-react-declarative/app/layout/ErrorLayout/ErrorLayout.tsx +41 -0
  85. package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
  86. package/full-react-declarative/app/layout/SecurityLayout/SecurityLayout.tsx +39 -0
  87. package/full-react-declarative/app/middleware/AuthMiddleware.ts +85 -0
  88. package/full-react-declarative/app/models/Comment.ts +31 -0
  89. package/full-react-declarative/app/models/Post.ts +22 -0
  90. package/full-react-declarative/app/models/User.ts +62 -0
  91. package/full-react-declarative/app/pages/home/HomePage.tsx +44 -0
  92. package/full-react-declarative/app/pages/login/LoginPage.css +0 -0
  93. package/full-react-declarative/app/pages/login/LoginPage.tsx +73 -0
  94. package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.css +0 -0
  95. package/full-react-declarative/app/pages/posts/CreatePostPage/CreatePostPage.tsx +67 -0
  96. package/full-react-declarative/app/pages/posts/PostPage/PostPage.tsx +60 -0
  97. package/full-react-declarative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +83 -0
  98. package/full-react-declarative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +77 -0
  99. package/full-react-declarative/app/pages/register/RegisterPage.tsx +68 -0
  100. package/full-react-declarative/app/pages/users/CreateUserPage.tsx +48 -0
  101. package/full-react-declarative/app/pages/users/ShowUserPage.tsx +62 -0
  102. package/full-react-declarative/app/pages/users/UpdateUserPage.tsx +57 -0
  103. package/full-react-declarative/app/pages/users/UserPage.tsx +57 -0
  104. package/full-react-declarative/app/providers/AppServiceProvider.ts +43 -0
  105. package/full-react-declarative/app/services/CommentService.ts +59 -0
  106. package/full-react-declarative/app/services/PostService.ts +108 -0
  107. package/full-react-declarative/app/services/SecurityService.ts +80 -0
  108. package/full-react-declarative/app/services/TokenService.ts +116 -0
  109. package/full-react-declarative/app/services/UserService.ts +126 -0
  110. package/full-react-declarative/app/utils.ts +17 -0
  111. package/full-react-declarative/assets/css/index.css +301 -0
  112. package/full-react-declarative/assets/img/logo.png +0 -0
  113. package/full-react-declarative/package.json +46 -0
  114. package/full-react-declarative/public/logo.png +0 -0
  115. package/full-react-declarative/public/vite.svg +1 -0
  116. package/full-react-declarative/stone.config.mjs +12 -0
  117. package/full-react-declarative/tsconfig.json +29 -0
  118. package/full-react-declarative/vitest.config.ts +24 -0
  119. package/full-react-imperative/.env.example +1 -0
  120. package/full-react-imperative/.env.public.example +1 -0
  121. package/full-react-imperative/LICENSE +21 -0
  122. package/full-react-imperative/README.md +39 -0
  123. package/full-react-imperative/app/Application.ts +79 -0
  124. package/full-react-imperative/app/clients/AxiosClient.ts +124 -0
  125. package/full-react-imperative/app/clients/CommentClient.ts +57 -0
  126. package/full-react-imperative/app/clients/PostClient.ts +86 -0
  127. package/full-react-imperative/app/clients/SecurityClient.ts +60 -0
  128. package/full-react-imperative/app/clients/UserClient.ts +93 -0
  129. package/full-react-imperative/app/clients/contracts/IAxiosClient.ts +97 -0
  130. package/full-react-imperative/app/clients/contracts/ICommentClient.ts +31 -0
  131. package/full-react-imperative/app/clients/contracts/IPostClient.ts +55 -0
  132. package/full-react-imperative/app/clients/contracts/ISecurityClient.ts +33 -0
  133. package/full-react-imperative/app/clients/contracts/IUserClient.ts +61 -0
  134. package/full-react-imperative/app/components/ChangePasswordForm/ChangePasswordForm.tsx +50 -0
  135. package/full-react-imperative/app/components/CommentForm/CommentForm.css +35 -0
  136. package/full-react-imperative/app/components/CommentForm/CommentForm.tsx +45 -0
  137. package/full-react-imperative/app/components/CommentItem/CommentItem.css +74 -0
  138. package/full-react-imperative/app/components/CommentItem/CommentItem.tsx +62 -0
  139. package/full-react-imperative/app/components/CommentWidget/CommentWidget.css +25 -0
  140. package/full-react-imperative/app/components/CommentWidget/CommentWidget.tsx +119 -0
  141. package/full-react-imperative/app/components/Dropdown/Dropdown.css +52 -0
  142. package/full-react-imperative/app/components/Dropdown/Dropdown.tsx +40 -0
  143. package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.css +62 -0
  144. package/full-react-imperative/app/components/LayoutHeader/LayoutHeader.tsx +61 -0
  145. package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.css +25 -0
  146. package/full-react-imperative/app/components/LayoutLeftMenu/LayoutLeftMenu.tsx +32 -0
  147. package/full-react-imperative/app/components/LoginForm/LoginForm.css +0 -0
  148. package/full-react-imperative/app/components/LoginForm/LoginForm.tsx +71 -0
  149. package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.css +41 -0
  150. package/full-react-imperative/app/components/NotificationBadge/NotificationBadge.tsx +63 -0
  151. package/full-react-imperative/app/components/PostCard/PostCard.css +129 -0
  152. package/full-react-imperative/app/components/PostCard/PostCard.tsx +65 -0
  153. package/full-react-imperative/app/components/PostForm/PostForm.css +92 -0
  154. package/full-react-imperative/app/components/PostForm/PostForm.tsx +76 -0
  155. package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.css +65 -0
  156. package/full-react-imperative/app/components/PostSkeleton/PostSkeleton.tsx +25 -0
  157. package/full-react-imperative/app/components/PostWidget/PostWidget.tsx +95 -0
  158. package/full-react-imperative/app/components/ProfileForm/ProfileForm.css +84 -0
  159. package/full-react-imperative/app/components/ProfileForm/ProfileForm.tsx +79 -0
  160. package/full-react-imperative/app/components/RegisterForm/RegisterForm.tsx +110 -0
  161. package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.css +32 -0
  162. package/full-react-imperative/app/components/RightAsidePanel/RightAsidePanel.tsx +62 -0
  163. package/full-react-imperative/app/components/SettingsForm/SettingsForm.css +126 -0
  164. package/full-react-imperative/app/components/SettingsForm/SettingsForm.tsx +86 -0
  165. package/full-react-imperative/app/components/UserAvatar/UserAvatar.css +18 -0
  166. package/full-react-imperative/app/components/UserAvatar/UserAvatar.tsx +60 -0
  167. package/full-react-imperative/app/components/UserBadge/UserBadge.css +33 -0
  168. package/full-react-imperative/app/components/UserBadge/UserBadge.tsx +49 -0
  169. package/full-react-imperative/app/components/UserCard/UserCard.css +70 -0
  170. package/full-react-imperative/app/components/UserCard/UserCard.tsx +43 -0
  171. package/full-react-imperative/app/configurations/AppConfiguration.ts +19 -0
  172. package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.css +0 -0
  173. package/full-react-imperative/app/error-pages/DefaultErrorPage/DefaultErrorPage.tsx +41 -0
  174. package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.css +0 -0
  175. package/full-react-imperative/app/error-pages/ForbiddenErrorPage/ForbiddenErrorPage.tsx +42 -0
  176. package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.css +0 -0
  177. package/full-react-imperative/app/error-pages/NotFoundErrorPage/NotFoundErrorPage.tsx +49 -0
  178. package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.css +0 -0
  179. package/full-react-imperative/app/error-pages/UnauthorizedErrorPage/UnauthorizedErrorPage.tsx +42 -0
  180. package/full-react-imperative/app/errors/ForbiddenError.ts +11 -0
  181. package/full-react-imperative/app/errors/PostNotFoundError.ts +11 -0
  182. package/full-react-imperative/app/errors/UnauthorizedError.ts +11 -0
  183. package/full-react-imperative/app/errors/UserNotFoundError.ts +11 -0
  184. package/full-react-imperative/app/events/UserEvent.ts +18 -0
  185. package/full-react-imperative/app/layout/AppLayout/AppLayout.css +106 -0
  186. package/full-react-imperative/app/layout/AppLayout/AppLayout.tsx +48 -0
  187. package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.css +0 -0
  188. package/full-react-imperative/app/layout/ErrorLayout/ErrorLayout.tsx +45 -0
  189. package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.css +0 -0
  190. package/full-react-imperative/app/layout/SecurityLayout/SecurityLayout.tsx +43 -0
  191. package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.css +99 -0
  192. package/full-react-imperative/app/layout/SettingsLayout/SettingsLayout.tsx +44 -0
  193. package/full-react-imperative/app/middleware/AuthMiddleware.ts +56 -0
  194. package/full-react-imperative/app/models/Comment.ts +35 -0
  195. package/full-react-imperative/app/models/Post.ts +27 -0
  196. package/full-react-imperative/app/models/User.ts +68 -0
  197. package/full-react-imperative/app/pages/Settings/SettingsPage.tsx +23 -0
  198. package/full-react-imperative/app/pages/home/HomePage.tsx +58 -0
  199. package/full-react-imperative/app/pages/login/LoginPage.css +0 -0
  200. package/full-react-imperative/app/pages/login/LoginPage.tsx +65 -0
  201. package/full-react-imperative/app/pages/posts/ShowPostPage/ShowPostPage.tsx +64 -0
  202. package/full-react-imperative/app/pages/posts/UpdatePostPage/UpdatePostPage.tsx +56 -0
  203. package/full-react-imperative/app/pages/register/RegisterPage.tsx +71 -0
  204. package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.css +64 -0
  205. package/full-react-imperative/app/pages/users/ShowUserPage/ShowUserPage.tsx +104 -0
  206. package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.css +0 -0
  207. package/full-react-imperative/app/pages/users/UpdateUserPage/UpdateUserPage.tsx +43 -0
  208. package/full-react-imperative/app/pages/users/UserPage/UserPage.css +31 -0
  209. package/full-react-imperative/app/pages/users/UserPage/UserPage.tsx +59 -0
  210. package/full-react-imperative/app/pages/utils.ts +67 -0
  211. package/full-react-imperative/app/providers/AppServiceProvider.ts +40 -0
  212. package/full-react-imperative/app/services/CommentService.ts +53 -0
  213. package/full-react-imperative/app/services/PostService.ts +102 -0
  214. package/full-react-imperative/app/services/SecurityService.ts +72 -0
  215. package/full-react-imperative/app/services/TokenService.ts +108 -0
  216. package/full-react-imperative/app/services/UserService.ts +115 -0
  217. package/full-react-imperative/app/services/contracts/ICommentService.ts +30 -0
  218. package/full-react-imperative/app/services/contracts/IPostService.ts +65 -0
  219. package/full-react-imperative/app/services/contracts/ISecurityService.ts +39 -0
  220. package/full-react-imperative/app/services/contracts/ITokenService.ts +44 -0
  221. package/full-react-imperative/app/services/contracts/IUserService.ts +70 -0
  222. package/full-react-imperative/app/utils.ts +31 -0
  223. package/full-react-imperative/assets/css/index.css +301 -0
  224. package/full-react-imperative/assets/img/logo.png +0 -0
  225. package/full-react-imperative/package.json +48 -0
  226. package/full-react-imperative/public/logo.png +0 -0
  227. package/full-react-imperative/public/vite.svg +1 -0
  228. package/full-react-imperative/stone.config.mjs +12 -0
  229. package/full-react-imperative/tsconfig.json +29 -0
  230. package/full-react-imperative/vitest.config.ts +24 -0
  231. package/full-service-declarative/.env.example +2 -0
  232. package/full-service-declarative/LICENSE +21 -0
  233. package/full-service-declarative/README.md +65 -0
  234. package/full-service-declarative/app/Application.ts +327 -0
  235. package/full-service-declarative/app/commands/ListSessionsCommand.ts +70 -0
  236. package/full-service-declarative/app/commands/ListUsersCommand.ts +56 -0
  237. package/full-service-declarative/app/configurations/AppConfiguration.ts +52 -0
  238. package/full-service-declarative/app/configurations/UserLiveConfiguration.ts +28 -0
  239. package/full-service-declarative/app/database/DatabaseClient.ts +43 -0
  240. package/full-service-declarative/app/database/schema.ts +43 -0
  241. package/full-service-declarative/app/error-handlers/SecurityErrorHandler.ts +61 -0
  242. package/full-service-declarative/app/errors/CredentialsError.ts +12 -0
  243. package/full-service-declarative/app/events/UserEvent.ts +17 -0
  244. package/full-service-declarative/app/handlers/CommentEventHandler.ts +103 -0
  245. package/full-service-declarative/app/handlers/PostEventHandler.ts +104 -0
  246. package/full-service-declarative/app/handlers/SecurityEventHandler.ts +108 -0
  247. package/full-service-declarative/app/handlers/UserEventHandler.ts +159 -0
  248. package/full-service-declarative/app/listeners/UserEventListener.ts +35 -0
  249. package/full-service-declarative/app/middleware/AuthMiddleware.ts +54 -0
  250. package/full-service-declarative/app/models/Comment.ts +38 -0
  251. package/full-service-declarative/app/models/Post.ts +50 -0
  252. package/full-service-declarative/app/models/Session.ts +14 -0
  253. package/full-service-declarative/app/models/User.ts +77 -0
  254. package/full-service-declarative/app/providers/DrizzleServiceProvider.ts +59 -0
  255. package/full-service-declarative/app/repositories/CommentRepository.ts +155 -0
  256. package/full-service-declarative/app/repositories/PostRepository.ts +138 -0
  257. package/full-service-declarative/app/repositories/SessionRepository.ts +123 -0
  258. package/full-service-declarative/app/repositories/UserRepository.ts +99 -0
  259. package/full-service-declarative/app/services/CommentService.ts +112 -0
  260. package/full-service-declarative/app/services/PostService.ts +100 -0
  261. package/full-service-declarative/app/services/SecurityService.ts +232 -0
  262. package/full-service-declarative/app/services/SessionService.ts +130 -0
  263. package/full-service-declarative/app/services/UserService.ts +110 -0
  264. package/full-service-declarative/app/subscribers/UserEventSubscriber.ts +38 -0
  265. package/full-service-declarative/drizzle.config.ts +13 -0
  266. package/full-service-declarative/package.json +48 -0
  267. package/full-service-declarative/stone.config.mjs +12 -0
  268. package/full-service-declarative/tsconfig.json +25 -0
  269. package/full-service-declarative/vitest.config.ts +24 -0
  270. package/full-service-imperative/.env.example +2 -0
  271. package/full-service-imperative/LICENSE +21 -0
  272. package/full-service-imperative/README.md +65 -0
  273. package/full-service-imperative/app/Application.ts +317 -0
  274. package/full-service-imperative/app/commands/ListSessionsCommand.ts +54 -0
  275. package/full-service-imperative/app/commands/ListUsersCommand.ts +42 -0
  276. package/full-service-imperative/app/configurations/AppConfiguration.ts +44 -0
  277. package/full-service-imperative/app/configurations/UserLiveConfiguration.ts +26 -0
  278. package/full-service-imperative/app/database/DatabaseClient.ts +39 -0
  279. package/full-service-imperative/app/database/schema.ts +43 -0
  280. package/full-service-imperative/app/error-handlers/SecurityErrorHandler.ts +58 -0
  281. package/full-service-imperative/app/errors/CredentialsError.ts +12 -0
  282. package/full-service-imperative/app/events/UserEvent.ts +17 -0
  283. package/full-service-imperative/app/handlers/CommentEventHandler.ts +99 -0
  284. package/full-service-imperative/app/handlers/PostEventHandler.ts +99 -0
  285. package/full-service-imperative/app/handlers/SecurityEventHandler.ts +83 -0
  286. package/full-service-imperative/app/handlers/UserEventHandler.ts +132 -0
  287. package/full-service-imperative/app/listeners/UserEventListener.ts +23 -0
  288. package/full-service-imperative/app/middleware/AuthMiddleware.ts +44 -0
  289. package/full-service-imperative/app/models/Comment.ts +38 -0
  290. package/full-service-imperative/app/models/Post.ts +50 -0
  291. package/full-service-imperative/app/models/Session.ts +14 -0
  292. package/full-service-imperative/app/models/User.ts +77 -0
  293. package/full-service-imperative/app/providers/DrizzleServiceProvider.ts +56 -0
  294. package/full-service-imperative/app/repositories/CommentRepository.ts +148 -0
  295. package/full-service-imperative/app/repositories/PostRepository.ts +130 -0
  296. package/full-service-imperative/app/repositories/SessionRepository.ts +115 -0
  297. package/full-service-imperative/app/repositories/UserRepository.ts +91 -0
  298. package/full-service-imperative/app/repositories/contracts/ICommentRepository.ts +72 -0
  299. package/full-service-imperative/app/repositories/contracts/IPostRepository.ts +63 -0
  300. package/full-service-imperative/app/repositories/contracts/ISessionRepository.ts +65 -0
  301. package/full-service-imperative/app/repositories/contracts/IUserRepository.ts +55 -0
  302. package/full-service-imperative/app/services/CommentService.ts +109 -0
  303. package/full-service-imperative/app/services/PostService.ts +97 -0
  304. package/full-service-imperative/app/services/SecurityService.ts +224 -0
  305. package/full-service-imperative/app/services/SessionService.ts +124 -0
  306. package/full-service-imperative/app/services/UserService.ts +105 -0
  307. package/full-service-imperative/app/services/contracts/ICommentService.ts +62 -0
  308. package/full-service-imperative/app/services/contracts/IPostService.ts +53 -0
  309. package/full-service-imperative/app/services/contracts/ISecurityService.ts +97 -0
  310. package/full-service-imperative/app/services/contracts/ISessionService.ts +73 -0
  311. package/full-service-imperative/app/services/contracts/IUserService.ts +57 -0
  312. package/full-service-imperative/app/subscribers/UserEventSubscriber.ts +28 -0
  313. package/full-service-imperative/drizzle.config.ts +13 -0
  314. package/full-service-imperative/package.json +48 -0
  315. package/full-service-imperative/stone.config.mjs +12 -0
  316. package/full-service-imperative/tsconfig.json +25 -0
  317. package/full-service-imperative/vitest.config.ts +24 -0
  318. package/package.json +225 -0
  319. package/standard-react-declarative/LICENSE +21 -0
  320. package/standard-react-declarative/README.md +39 -0
  321. package/standard-react-declarative/app/Application.ts +45 -0
  322. package/standard-react-declarative/app/pages/welcome/WelcomePage.tsx +57 -0
  323. package/standard-react-declarative/app/services/WelcomeService.ts +38 -0
  324. package/standard-react-declarative/assets/css/index.css +26 -0
  325. package/standard-react-declarative/package.json +42 -0
  326. package/standard-react-declarative/tsconfig.json +33 -0
  327. package/standard-react-declarative/vitest.config.ts +24 -0
  328. package/standard-react-imperative/LICENSE +21 -0
  329. package/standard-react-imperative/README.md +39 -0
  330. package/standard-react-imperative/app/Application.ts +41 -0
  331. package/standard-react-imperative/app/pages/welcome/WelcomePage.tsx +50 -0
  332. package/standard-react-imperative/app/services/WelcomeService.ts +38 -0
  333. package/standard-react-imperative/assets/css/index.css +26 -0
  334. package/standard-react-imperative/package.json +42 -0
  335. package/standard-react-imperative/tsconfig.json +33 -0
  336. package/standard-react-imperative/vitest.config.ts +24 -0
  337. package/standard-service-declarative/LICENSE +21 -0
  338. package/standard-service-declarative/README.md +39 -0
  339. package/standard-service-declarative/app/Application.ts +39 -0
  340. package/standard-service-declarative/app/handlers/WelcomeEventHandler.ts +45 -0
  341. package/standard-service-declarative/app/services/WelcomeService.ts +38 -0
  342. package/standard-service-declarative/package.json +36 -0
  343. package/standard-service-declarative/tsconfig.json +25 -0
  344. package/standard-service-declarative/vitest.config.ts +24 -0
  345. package/standard-service-imperative/LICENSE +21 -0
  346. package/standard-service-imperative/README.md +39 -0
  347. package/standard-service-imperative/app/Application.ts +11 -0
  348. package/standard-service-imperative/app/handlers/welcomeEventHandler.ts +31 -0
  349. package/standard-service-imperative/app/services/welcomeService.ts +38 -0
  350. package/standard-service-imperative/package.json +35 -0
  351. package/standard-service-imperative/tsconfig.json +25 -0
  352. 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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }