-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Challenge tabs #90
base: main
Are you sure you want to change the base?
Challenge tabs #90
Changes from all commits
1e841a5
14b30be
1be63b8
f86e7dd
aada9cc
f9f77f4
5cb02e5
1c9dd6a
63afbfc
275a3a6
423999f
a277544
8140d41
a9b9d3a
ec678c3
ebb4cc9
ae61fe4
2d476a0
0f1a795
acbb1a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Card } from 'ui'; | ||
import { getTimeDiffFromTimestamp } from 'utils/timeDifference/getTimeDiffFromTimestamp'; | ||
import type { Comment } from '../../../types/types'; | ||
import { ReactComponent as Reply } from '/components/icons/reply.svg'; | ||
import { ReactComponent as Like } from '/components/icons/like.svg'; | ||
import { UserAvatar } from 'molecules/userAvatar/userAvatar'; | ||
|
||
type CommentItemProps = Comment; | ||
|
||
export const CommentItem = ({ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
id, | ||
author, | ||
comment, | ||
timestamp, | ||
}: CommentItemProps) => { | ||
return ( | ||
<div className="flex-col w-full py-2 mx-auto bg-white sm:px-4 md:px-4 md:w-2/3"> | ||
<Card tag="div"> | ||
<div className="flex flex-row md-10"> | ||
<UserAvatar avatar={author.avatar_URL} size="12" /> | ||
<div className="flex-col mt-1"> | ||
<div className="flex items-center flex-1 px-4 font-bold leading-tight"> | ||
{author.name} | ||
<span className="ml-2 text-xs font-normal text-gray-500"> | ||
{getTimeDiffFromTimestamp(timestamp)} | ||
</span> | ||
</div> | ||
<div className="flex-1 px-2 ml-2 text-sm font-medium leading-loose text-gray-600"> | ||
{comment} | ||
</div> | ||
<button className="inline-flex items-center px-1 pt-2 ml-1 flex-column"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This 2 |
||
<div className="w-5 h-5"> | ||
<Reply /> | ||
</div> | ||
</button> | ||
<button className="inline-flex items-center px-1 -ml-1 flex-column"> | ||
<div className="w-5 h-5"> | ||
<Like /> | ||
</div> | ||
</button> | ||
</div> | ||
</div> | ||
</Card> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import type { Comment } from '../../../types/types'; | ||
import { ReactComponent as Reply } from '/components/icons/reply.svg'; | ||
import { ReactComponent as Liked } from '/components/icons/liked.svg'; | ||
import { getTimeDiffFromTimestamp } from 'utils/timeDifference/getTimeDiffFromTimestamp'; | ||
import { UserAvatar } from 'molecules/userAvatar/userAvatar'; | ||
|
||
type CommentItemWithReplyProps = Comment; | ||
|
||
export const CommentReply = ({ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
id, | ||
author, | ||
timestamp, | ||
comment, | ||
}: CommentItemWithReplyProps) => { | ||
// TODO: Add reply functionality | ||
return ( | ||
<> | ||
<hr className="my-2 ml-16 border-gray-200" /> | ||
<div className="flex flex-row pt-1 md-10 md:ml-16"> | ||
<UserAvatar avatar={author.avatar_URL} size={12} /> | ||
<div className="flex-col mt-1"> | ||
<div className="flex items-center flex-1 px-4 font-bold leading-tight"> | ||
{author.name} | ||
<span className="ml-2 text-xs font-normal text-gray-500"> | ||
{getTimeDiffFromTimestamp(timestamp)} | ||
</span> | ||
</div> | ||
<div className="flex-1 px-2 ml-2 text-sm font-medium leading-loose text-gray-600"> | ||
{comment} | ||
</div> | ||
<button className="inline-flex items-center px-1 pt-2 ml-1 flex-column"> | ||
<div className="w-5 h-5"> | ||
<Reply /> | ||
</div> | ||
</button> | ||
<button className="inline-flex items-center px-1 -ml-1 flex-column"> | ||
<div className="w-5 h-5"> | ||
<Liked /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This buttons with icons are a good candidate for a separate component as well ;) |
||
</div> | ||
</button> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { Comment } from '../../../types/types'; | ||
|
||
export const commentsMock: Comment[] = [ | ||
{ | ||
id: '1', | ||
author: { | ||
id: '1', | ||
name: 'Adam Nowak', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1633332755192-727a05c4013d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2960&q=80', | ||
}, | ||
comment: | ||
'To zadanie frontendowe wydaje się bardzo wymagające, ale na pewno pozwoli na rozwinięcie umiejętności i poszerzenie wiedzy. Trzeba będzie zwrócić uwagę na każdy szczegół, aby stworzyć estetyczny i responsywny interfejs.', | ||
timestamp: 1264938840000, | ||
}, | ||
|
||
{ | ||
id: '2', | ||
author: { | ||
id: '2', | ||
name: 'Maria Wójcik', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1509839862600-309617c3201e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', | ||
}, | ||
comment: | ||
'Mam nadzieję, że w tym zadaniu będzie można wykorzystać najnowsze technologie i narzędzia, co pozwoli na jeszcze lepsze efekty. Czekam na wyzwania, które pozwolą mi się rozwijać i poszerzać horyzonty.', | ||
timestamp: 1678794840000, | ||
}, | ||
|
||
{ | ||
id: '3', | ||
author: { | ||
id: '3', | ||
name: 'Piotr Kowalczyk', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1556157382-97eda2d62296?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', | ||
}, | ||
comment: | ||
'Zadanie frontendowe to wspaniała okazja, aby pokazać swoje umiejętności projektowania interfejsów użytkownika. Nie mogę się doczekać, aby zacząć pracę i zobaczyć, co uda mi się stworzyć.', | ||
timestamp: 1672444800000, | ||
}, | ||
|
||
{ | ||
id: '4', | ||
author: { | ||
id: '4', | ||
name: 'Karolina Nowakowska', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1607982863027-0cb6818ee8b7?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', | ||
}, | ||
comment: | ||
'Zadanie frontendowe może być trudne, ale warto podjąć wyzwanie. Będzie to okazja do nauki nowych technologii i rozwoju umiejętności, co na pewno będzie przydatne w dalszej karierze.', | ||
timestamp: 1678808591856, | ||
}, | ||
]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Heading } from 'ui'; | ||
import { ProtectedComponent } from 'organisms/protectedComponent/protectedComponent'; | ||
import { AddComment } from 'organisms/addComment/addComment'; | ||
import { CommentItem } from 'molecules/commentItem/commentItem'; | ||
import { commentsMock } from 'molecules/comments/comments.mock'; | ||
|
||
const comments = commentsMock.sort((a, b) => b.timestamp - a.timestamp); | ||
ssynowiec marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export const Comments = () => { | ||
return ( | ||
<div> | ||
<div className="flex-col w-full py-2 mx-auto bg-white sm:px-4 md:px-4 md:w-2/3"> | ||
<div className="pb-2"> | ||
<Heading tag="h3" size="medium"> | ||
Komentarze ({comments.length}) | ||
</Heading> | ||
</div> | ||
<ProtectedComponent info="Aby dodać komentarz musisz być zalogowany"> | ||
<AddComment /> | ||
</ProtectedComponent> | ||
</div> | ||
{comments.map((comment) => ( | ||
<CommentItem {...comment} key={comment.id} /> | ||
))} | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Card, Heading, Text } from 'ui'; | ||
import clsx from 'clsx'; | ||
import type { Opinion } from '../../../types/types'; | ||
import { UserAvatar } from 'molecules/userAvatar/userAvatar'; | ||
|
||
type OpinionItemProps = Opinion; | ||
|
||
export const OpinionItem = ({ author, rating, comment }: OpinionItemProps) => { | ||
return ( | ||
<div className="p-2"> | ||
<Card tag="div"> | ||
<div className="flex flex-col md:flex-row justify-center items-center"> | ||
<UserAvatar avatar={author.avatar_URL} /> | ||
<div className="md:pl-5"> | ||
<Heading tag="h3" size="large" className="font-bold"> | ||
{author.name} | ||
</Heading> | ||
<div className="flex items-center"> | ||
{Array.from({ length: 5 }, (_, i) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would extract this 5 to some constant. Also I'd create an array with some meaningful name and put it outside of the component as it is static. |
||
const starClass = | ||
i < Math.round(rating) ? 'text-yellow-400' : 'text-gray-300'; | ||
return ( | ||
<svg | ||
aria-hidden="true" | ||
className={clsx('w-5 h-5', starClass)} | ||
fill="currentColor" | ||
viewBox="0 0 20 20" | ||
xmlns="http://www.w3.org/2000/svg" | ||
key={i} | ||
> | ||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path> | ||
</svg> | ||
); | ||
})} | ||
</div> | ||
<Text size="medium" tag="p" variant="default" position="left"> | ||
{comment} | ||
</Text> | ||
</div> | ||
</div> | ||
</Card> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import type { Opinion } from '../../../types/types'; | ||
|
||
export const opinions: Opinion[] = [ | ||
{ | ||
id: '1', | ||
author: { | ||
id: '1', | ||
name: 'Adam Nowak', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1633332755192-727a05c4013d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2960&q=80', | ||
}, | ||
rating: 5, | ||
comment: | ||
'Zadanie programistyczne, które otrzymałem, było dobrze sformułowane i precyzyjnie opisywało wymagania dotyczące tworzenia aplikacji internetowej. Zadanie miało na celu zaimplementowanie funkcjonalności wyszukiwania produktów w bazie danych i wyświetlenia wyników na stronie internetowej.', | ||
}, | ||
{ | ||
id: '2', | ||
author: { | ||
id: '2', | ||
name: 'Maria Wójcik', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1509839862600-309617c3201e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', | ||
}, | ||
rating: 5, | ||
comment: | ||
'Zadanie programistyczne, które otrzymałem, było dobrze sformułowane i precyzyjnie opisywało wymagania dotyczące tworzenia aplikacji internetowej. Zadanie miało na celu zaimplementowanie funkcjonalności wyszukiwania produktów w bazie danych i wyświetlenia wyników na stronie internetowej.', | ||
}, | ||
{ | ||
id: '3', | ||
author: { | ||
id: '3', | ||
name: 'Piotr Kowalczyk', | ||
avatar_URL: | ||
'https://images.unsplash.com/photo-1556157382-97eda2d62296?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80', | ||
}, | ||
rating: 4, | ||
comment: | ||
'Zadanie programistyczne, które otrzymałem, było dobrze sformułowane i precyzyjnie opisywało wymagania dotyczące tworzenia aplikacji internetowej. Zadanie miało na celu zaimplementowanie funkcjonalności wyszukiwania produktów w bazie danych i wyświetlenia wyników na stronie internetowej.', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this is mock data but it would be cool to see some variety and how it looks and behaves with different lengths of the comments. 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. User can't give negative or above 5 rating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any validation for that on the backend? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think not now |
||
}, | ||
]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { OpinionItem } from 'molecules/opinionItem/opinionItem'; | ||
import { AddOpinion } from 'organisms/addOpinion/addOpinion'; | ||
import { OpinionStats } from 'molecules/opinonStats/opinionStats'; | ||
import { ProtectedComponent } from 'organisms/protectedComponent/protectedComponent'; | ||
import { opinions } from 'molecules/opinions/opinions.mock'; | ||
|
||
export const Opinions = () => { | ||
return ( | ||
<> | ||
<div className="flex flex-col md:flex-row"> | ||
<div className="p-2 w-full md:w-1/2"> | ||
<ProtectedComponent info="Zaloguj się aby dodać opinię."> | ||
<AddOpinion /> | ||
</ProtectedComponent> | ||
</div> | ||
<OpinionStats opinions={opinions} /> | ||
</div> | ||
{opinions.map((opinion, id) => ( | ||
<OpinionItem key={id} {...opinion} /> | ||
))} | ||
</> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make a
comment: Comment
prop accepting an object. No need for spreading then and you have everything contained in one objectThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but you neeed to destructure it later or write redundant object prop calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather have a param destructurization than something like that tbh.
As for now the
CommentItemProps
is redundant as the props could be directly typed asComment
.I used to spread props but over the time I learned in most of the cases it is better to explicitly pass props. There are some exceptions ofc (for example
register
function for form libs)