update crc cards post
This commit is contained in:
11
components.d.ts
vendored
11
components.d.ts
vendored
@@ -1,11 +1,8 @@
|
|||||||
// generated by unplugin-vue-components
|
// generated by unplugin-vue-components
|
||||||
// We suggest you to commit this file into source control
|
// We suggest you to commit this file into source control
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/vue-next/pull/3399
|
||||||
import '@vue/runtime-core'
|
|
||||||
|
|
||||||
export {}
|
declare module 'vue' {
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AboutMe: typeof import('./src/components/presentation/about-me.vue')['default']
|
AboutMe: typeof import('./src/components/presentation/about-me.vue')['default']
|
||||||
AppHeader: typeof import('./src/components/app-header.vue')['default']
|
AppHeader: typeof import('./src/components/app-header.vue')['default']
|
||||||
@@ -16,8 +13,8 @@ declare module '@vue/runtime-core' {
|
|||||||
MyBooks: typeof import('./src/components/presentation/my-books.vue')['default']
|
MyBooks: typeof import('./src/components/presentation/my-books.vue')['default']
|
||||||
MyProjects: typeof import('./src/components/presentation/my-projects.vue')['default']
|
MyProjects: typeof import('./src/components/presentation/my-projects.vue')['default']
|
||||||
ProductionFlow: typeof import('./src/components/flow/ProductionFlow.vue')['default']
|
ProductionFlow: typeof import('./src/components/flow/ProductionFlow.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
|
||||||
Welcome: typeof import('./src/components/Welcome.vue')['default']
|
Welcome: typeof import('./src/components/Welcome.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { }
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
padding: 2rem;
|
padding: 1.2rem;
|
||||||
|
margin: 1rem 2rem;
|
||||||
border-radius: 0.3em;
|
border-radius: 0.3em;
|
||||||
background-color: #574b90;
|
background-color: #574b90;
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ export const UserBookmarks: FunctionComponent<Props> = ({ user }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return <div className="user-bookmarks">
|
return <div className="user-bookmarks">
|
||||||
<Title title={strings['frontoffice.bookmark.user_bookmarks']} />
|
<Title title={i18n('bookmark.user_bookmarks')} />
|
||||||
{isLoading
|
{isLoading
|
||||||
? <TilesSkeleton animation={tilesAnimation} numberOfTiles={16} />
|
? <TilesSkeleton animation={tilesAnimation} numberOfTiles={16} />
|
||||||
: <BookmarkItem
|
: <BookmarkItem
|
||||||
@@ -87,9 +87,8 @@ export const UserBookmarks: FunctionComponent<Props> = ({ user }) => {
|
|||||||
/>}
|
/>}
|
||||||
|
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
text={strings['frontoffice.bookmark.all_bookmarks']}
|
text={i18n('bookmark.add_bookmark')}
|
||||||
onClick={() => setShowAddBookmarkModal(true))}
|
onClick={() => setShowAddBookmarkModal(true))}
|
||||||
alt={'strings['frontoffice.bookmark.add_bookmarks']'}
|
|
||||||
image={<FontAwesomeIcon icon={['fas', 'plus']} color="white" />}
|
image={<FontAwesomeIcon icon={['fas', 'plus']} color="white" />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -128,91 +127,35 @@ But hey! We can already note the first responsability on our CRC card.
|
|||||||
As we are talking about inputs, I want to know how the props are used. Are they necessary? Are they sufficient? Here we can see that `user` is only used for fetching data:
|
As we are talking about inputs, I want to know how the props are used. Are they necessary? Are they sufficient? Here we can see that `user` is only used for fetching data:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
...
|
// ...
|
||||||
const userBookmark = await fetch(`/users/${user.id}/bookmarks`, {
|
const userBookmark = await fetch(`/users/${user.id}/bookmarks`, {
|
||||||
...
|
// ...
|
||||||
|
const newBookmark = await fetch(`/users/${user.id}/bookmarks`, {
|
||||||
|
// ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Only the `user id` is necessary, why not just give the userId instead of the whole object?
|
Only the `user id` is necessary, why not just give the user id instead of the whole object? That will be our first simplification.
|
||||||
|
|
||||||
> Here is a classic responsibility leak I frequentely see. Components don't care that user have a `user.address.line1` property when they only want their `id`.
|
> Here is a classic responsibility leak I frequentely see. When you're developing a feature, you have the big picture but `UserBookmarks` and its local knowledge don't care about the user having a `user.address.line1` property.
|
||||||
|
|
||||||
That will be our first simplification.
|
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
interface Props {
|
interface Props {
|
||||||
userId: number
|
userId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserBookmarks: FunctionComponent<Props> = ({ userID }) => {
|
export const UserBookmarks: FunctionComponent<Props> = ({ userId }) => {
|
||||||
const [bookmarks, setBookmarks] = useState<Bookmark[]>([])
|
// ...
|
||||||
const [showAddBookmarkModal, setShowAddBookmarkModal] = useState(false)
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const userBookmark = await fetch(`/users/${userId}/bookmarks`, {
|
const userBookmark = await fetch(`/users/${userId}/bookmarks`, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
})
|
})
|
||||||
setBookmarks(userBookmarks)
|
// ...
|
||||||
} catch (error) {
|
|
||||||
setBookmarks([])
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const addBookmarkToUser = async ({ bookmark }) => {
|
|
||||||
setIsLoading(true)
|
|
||||||
try {
|
|
||||||
const newBookmark = await fetch(`/users/${userId}/bookmarks`, {
|
const newBookmark = await fetch(`/users/${userId}/bookmarks`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ bookmark })
|
body: JSON.stringify({ bookmark })
|
||||||
})
|
})
|
||||||
setBookmarks([...bookmarks, newBookmark])
|
// ...
|
||||||
} catch (error) {
|
|
||||||
console.warn(error);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tilesAnimation = gsap.to({
|
|
||||||
duration: 0.8,
|
|
||||||
opacity: 0.35,
|
|
||||||
yoyo: true,
|
|
||||||
repeat: -1,
|
|
||||||
stagger: 0.025,
|
|
||||||
})
|
|
||||||
|
|
||||||
return <div className="user-bookmarks">
|
|
||||||
<Title title={strings['frontoffice.bookmark.user_bookmarks']} />
|
|
||||||
{isLoading
|
|
||||||
? <TilesSkeleton animation={tilesAnimation} numberOfTiles={16} />
|
|
||||||
: <BookmarkItem
|
|
||||||
key={bookmark.id}
|
|
||||||
data={bookmark}
|
|
||||||
/>}
|
|
||||||
|
|
||||||
<PrimaryButton
|
|
||||||
text={strings['frontoffice.bookmark.all_bookmarks']}
|
|
||||||
onClick={() => setShowAddBookmarkModal(true))}
|
|
||||||
alt={'strings['frontoffice.bookmark.add_bookmarks']'}
|
|
||||||
image={<FontAwesomeIcon icon={['fas', 'plus']} color="white" />}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AddBookmarkModal
|
|
||||||
visible={showAddBookmarkModal}
|
|
||||||
onClose={() => setShowAddBookmarkModal(false)}
|
|
||||||
bookmarks={bookmarks}
|
|
||||||
onBookmarkAdd={addBookmarkToUser}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## The secret sauce
|
## The secret sauce
|
||||||
|
|
||||||
Now comes where we'll definetely challenge how the component does its magic.
|
Now comes where we'll challenge how the component does its magic.
|
||||||
|
|||||||
Reference in New Issue
Block a user