mirror of
https://github.com/usatiuk/y.git
synced 2025-10-28 10:37:47 +01:00
posts prettier
This commit is contained in:
@@ -1,20 +1,14 @@
|
||||
import "./Auth.scss";
|
||||
import { Form, Link, useActionData, useNavigation } from "react-router-dom";
|
||||
import { loginAction } from "./actions";
|
||||
import { ActionToType, loginAction } from "./actions";
|
||||
import { isError } from "./api/dto";
|
||||
|
||||
export function Login() {
|
||||
const data = useActionData() as
|
||||
| Awaited<ReturnType<typeof loginAction>>
|
||||
| undefined;
|
||||
|
||||
if (data && !isError(data)) {
|
||||
return <div className="authForm">Login success</div>;
|
||||
}
|
||||
const data = useActionData() as ActionToType<typeof loginAction>;
|
||||
|
||||
let errors: JSX.Element[] = [];
|
||||
|
||||
if (data) {
|
||||
if (isError(data)) {
|
||||
errors = data.errors.map((e) => {
|
||||
return <a>{e}</a>;
|
||||
});
|
||||
|
||||
19
client/src/Post.scss
Normal file
19
client/src/Post.scss
Normal file
@@ -0,0 +1,19 @@
|
||||
.post {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #E0E0E0;
|
||||
border-radius: 7px;
|
||||
padding: 7px;
|
||||
resize: none;
|
||||
margin: 1rem 0;
|
||||
|
||||
.text {
|
||||
word-wrap: anywhere;
|
||||
}
|
||||
|
||||
.createdDate {
|
||||
margin-top: 0.3rem;
|
||||
font-size: 0.7rem;
|
||||
color: #A0A0A0;
|
||||
}
|
||||
}
|
||||
16
client/src/Post.tsx
Normal file
16
client/src/Post.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import "./Post.scss";
|
||||
|
||||
export function Post({
|
||||
text,
|
||||
createdDate,
|
||||
}: {
|
||||
text: string;
|
||||
createdDate: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={"post"}>
|
||||
<span className={"text"}>{text}</span>
|
||||
<span className={"createdDate"}>{createdDate}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -55,6 +55,6 @@
|
||||
}
|
||||
|
||||
.posts {
|
||||
padding: 2rem;
|
||||
padding: 0 2rem 2rem;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { Form, Link, useLoaderData } from "react-router-dom";
|
||||
import { LoaderToType, profileSelfLoader } from "./loaders";
|
||||
import { isError } from "./api/dto";
|
||||
import { ProfileCard } from "./ProfileCard";
|
||||
import { Post } from "./Post";
|
||||
|
||||
export interface IProfileProps {
|
||||
self: boolean;
|
||||
@@ -16,6 +17,11 @@ export function Profile(props: IProfileProps) {
|
||||
if (!loaderData || isError(loaderData)) {
|
||||
return <div>Error</div>;
|
||||
}
|
||||
|
||||
const sortedPosts = loaderData.posts?.sort(
|
||||
(a, b) => b.createdAt - a.createdAt,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={"profileView"}>
|
||||
<div className={"profileInfo"}>
|
||||
@@ -29,12 +35,15 @@ export function Profile(props: IProfileProps) {
|
||||
</Form>
|
||||
</div>
|
||||
<div className={"posts"}>
|
||||
{loaderData.posts &&
|
||||
loaderData.posts.map((p) => {
|
||||
{sortedPosts &&
|
||||
sortedPosts.map((p) => {
|
||||
const date = new Date(p.createdAt * 1000);
|
||||
return (
|
||||
<div key={p.id} className={"post"}>
|
||||
{p.text}
|
||||
</div>
|
||||
<Post
|
||||
text={p.text}
|
||||
createdDate={`${date.toUTCString()}`}
|
||||
key={p.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import "./Auth.scss";
|
||||
import { Form, Link, useActionData, useNavigation } from "react-router-dom";
|
||||
import { signupAction } from "./actions";
|
||||
import { ActionToType, signupAction } from "./actions";
|
||||
import { isError } from "./api/dto";
|
||||
|
||||
export function Signup() {
|
||||
const data = useActionData() as
|
||||
| Awaited<ReturnType<typeof signupAction>>
|
||||
| undefined;
|
||||
|
||||
if (data && !isError(data)) {
|
||||
return <div className="authForm">Signup success</div>;
|
||||
}
|
||||
const data = useActionData() as ActionToType<typeof signupAction>;
|
||||
|
||||
let errors: JSX.Element[] = [];
|
||||
|
||||
if (data) {
|
||||
if (isError(data)) {
|
||||
errors = data.errors.map((e) => {
|
||||
return <a>{e}</a>;
|
||||
});
|
||||
|
||||
@@ -5,6 +5,10 @@ import { isError } from "./api/dto";
|
||||
import { setToken } from "./api/utils";
|
||||
import { post } from "./api/Post";
|
||||
|
||||
export type ActionToType<T extends (...args: any) => any> =
|
||||
| Exclude<Awaited<ReturnType<T>>, Response>
|
||||
| undefined;
|
||||
|
||||
export async function loginAction({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const ret = await login(
|
||||
|
||||
@@ -45,6 +45,7 @@ export const PostTo = z.object({
|
||||
id: z.number(),
|
||||
authorUuid: z.string(),
|
||||
text: z.string(),
|
||||
createdAt: z.number(),
|
||||
});
|
||||
export type TPostTo = z.infer<typeof PostTo>;
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@ package com.usatiuk.tjv.y.server.dto;
|
||||
|
||||
import com.usatiuk.tjv.y.server.entity.Post;
|
||||
|
||||
public record PostTo(Long id, String authorUuid, String text) {
|
||||
public record PostTo(Long id, String authorUuid, String text, Long createdAt) {
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.usatiuk.tjv.y.server.dto.converters;
|
||||
|
||||
import com.usatiuk.tjv.y.server.dto.PersonTo;
|
||||
import com.usatiuk.tjv.y.server.dto.PostTo;
|
||||
import com.usatiuk.tjv.y.server.entity.Person;
|
||||
import com.usatiuk.tjv.y.server.entity.Post;
|
||||
|
||||
public class PostMapper {
|
||||
public static PostTo makeDto(Post post) {
|
||||
return new PostTo(post.getId(), post.getAuthor().getUuid(), post.getText());
|
||||
return new PostTo(post.getId(), post.getAuthor().getUuid(), post.getText(), post.getCreatedAt().getEpochSecond());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
package com.usatiuk.tjv.y.server.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@@ -21,9 +28,12 @@ public class Post implements EntityWithId<Long> {
|
||||
@ManyToOne
|
||||
private Person author;
|
||||
|
||||
@Lob
|
||||
@NotBlank
|
||||
private String text;
|
||||
|
||||
@CreationTimestamp
|
||||
private Instant createdAt;
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
||||
Reference in New Issue
Block a user