Fakultas Ilmu Komputer UI

Commit 01bf3008 authored by Nabila Febri Viola's avatar Nabila Febri Viola
Browse files

[CHORES] Fix conflicts

parents d19b0218 f685381c
Pipeline #48921 passed with stages
in 2 minutes and 34 seconds
......@@ -39,6 +39,7 @@ const Navbar = () => {
>
Ajukan Acara Donor
</Button>
<NavLink to="/kumpulan-artikel">Kumpulan Artikel</NavLink>
{user && <NavLink to="/profile">Profil</NavLink>}
</Nav>
{user ? (
......
......@@ -31,6 +31,8 @@ describe(`Navbar`, () => {
const { container } = render(<Navbar />)
expect(container).toHaveTextContent("Home")
expect(container).toHaveTextContent("Jadwal Donor")
expect(container).toHaveTextContent("Ajukan Acara Donor")
expect(container).toHaveTextContent("Kumpulan Artikel")
})
})
......
@media (min-width: 320px) {
.slider {
max-width: 500px;
margin: auto;
position: relative;
width: 100%;
height: 200px;
overflow: hidden;
border-radius: 10px;
margin-top: 2rem;
}
.slider a.previousButton,
.slider a.nextButton {
font-size: 22px;
line-height: 0;
display: block;
position: absolute;
top: 50%;
transform: translateY(-50%);
transition: all 0.3s linear;
z-index: 1;
color: var(--cream);
padding: 10px;
text-decoration: none;
backface-visibility: hidden; /* prevent jump effect when scaling */
}
.slider a.previousButton,
.slider a.nextButton:not(.disabled):hover {
transform: translateY(-50%) scale(1.25);
cursor: pointer;
}
.slider a.previousButton svg polygon,
.slider a.nextButton svg polygon {
fill: var(--cream);
}
.slider a.previousButton {
left: 20px;
}
.slider a.nextButton {
right: 20px;
}
.slide {
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
background-size: cover;
}
.slide.hidden {
visibility: hidden;
}
.slide.previous {
left: -100%;
}
.slide.current {
left: 0;
}
.slide.next {
left: 100%;
}
.slide.animateIn,
.slide.animateOut {
transition: all 2s ease;
}
.slide.animateIn.previous,
.slide.animateIn.next {
left: 0;
visibility: visible;
}
.slide.animateOut.previous {
left: 100%;
}
.slide.animateOut.next {
left: -100%;
}
.slider p {
display: block;
width: 60%;
text-align: center;
margin-left: 20%;
margin-top: 48%;
color: var(--cream);
position: relative;
}
}
@media (min-width: 405px) {
.slider p {
margin-top: 43%;
}
}
@media (min-width: 445px) {
.slider p {
margin-top: 40%;
}
}
@media (min-width: 480px) {
.slider p {
margin-top: 35%;
}
}
@media (min-width: 545px) {
.slider p {
margin-top: 30%;
}
}
@media (min-width: 620px) {
.slider p {
margin-top: 28%;
}
}
@media (min-width: 675px) {
.slider p {
margin-top: 25%;
}
}
@media (min-width: 745px) {
.slider p {
margin-top: 22%;
}
}
@media (min-width: 768px) {
.slider {
margin-top: 0rem;
}
.slider p {
margin-top: 43%;
}
}
@media (min-width: 880px) {
.slider p {
margin-top: 40%;
}
}
@media (min-width: 940px) {
.slider p {
margin-top: 38%;
}
}
@media (min-width: 990px) {
.slider p {
margin-top: 35%;
}
}
@media (min-width: 1100px) {
.slider p {
margin-top: 32%;
}
}
@media (min-width: 1180px) {
.slider p {
margin-top: 28%;
}
}
@media (min-width: 1250px) {
.slider p {
margin-top: 25%;
}
}
@media (min-width: 1400px) {
.slider p {
margin-top: 23%;
}
}
@media (min-width: 1450px) {
.slider {
width: 90%;
margin-left: 5%;
}
.slider p {
margin-top: 25%;
}
}
@media (min-width: 1500px) {
.slider {
width: 80%;
margin-left: 10%;
}
.slider p {
margin-top: 28%;
}
}
@media (min-width: 1650px) {
.slider p {
margin-top: 25%;
}
}
.article .column {
margin: 15px 15px 0;
padding: 0;
}
.article .column:last-child {
padding-bottom: 60px;
}
.article .column::after {
content: "";
clear: both;
display: block;
}
.article .column div {
position: relative;
float: left;
width: 300px;
margin: 0 0 0 25px;
padding: 0;
}
.article .column div:first-child {
margin-left: 0;
}
.article .column div span {
position: absolute;
bottom: -70px;
left: 0;
z-index: -1;
display: block;
width: 300px;
margin: 0;
padding: 0;
color: #444;
font-size: 18px;
text-decoration: none;
text-align: center;
-webkit-transition: 0.3s ease-in-out;
transition: 0.3s ease-in-out;
opacity: 0;
}
.article figure {
width: 300px;
margin: 0;
padding: 0;
background: #fff;
overflow: hidden;
}
.article figure:hover + span {
bottom: -55px;
opacity: 1;
}
import { Router } from "@reach/router"
import React from "react"
import { Col, Container, Row } from "react-bootstrap"
import { useQuery } from "react-query"
import { getArtikelEdukasi, getListArtikelEdukasi } from "../api"
import ErrorRetry from "../components/error-retry"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Spinner from "../components/spinner"
import { Link } from "gatsby"
import "./article.css"
const Content = props => {
const articleId = props.id
const { status, data, refetch } = useQuery(
["detail-artikel-edukasi", articleId],
() => getArtikelEdukasi(articleId)
)
const article = status === "success" ? data.data : {}
const content =
status === "success"
? article.content
.split("\n")
.map(text => "<p>" + text + "</p>")
.join(" ")
: ""
const {
status: statusList,
data: dataList,
refetch: refetchList,
} = useQuery("artikel-edukasi", () => getListArtikelEdukasi(1))
return (
<Layout navbar>
<SEO title={data ? data.data.title : "Artikel"} />
{status === "loading" ? (
<Spinner />
) : status === "error" ? (
<ErrorRetry retry={refetch} />
) : (
<Container className="article">
<Row>
<Col sm={8}>
<Row>
<h3 id="title">
<b className="text-red">{article.title}</b>
</h3>
<img
src={article.featured_image}
alt={article.title}
className="img-fluid rounded mx-auto d-block"
></img>
</Row>
<Row>
<Col className="bg-cream mx-3 py-5 my-5 text-justify">
<div dangerouslySetInnerHTML={{ __html: content }} />
</Col>
</Row>
</Col>
<Col sm={4}>
{statusList === "loading" ? (
<Spinner />
) : statusList === "error" ? (
<ErrorRetry retry={refetchList} />
) : (
dataList.data.results.slice(0, 3).map(newArticle => (
<Link to={"/article/" + newArticle.id} key={newArticle.id}>
<Row className="my-3">
<div className="column">
<div>
<figure>
<img
src={newArticle.featured_image}
alt={newArticle.title}
className="img-fluid rounded mx-auto d-block"
/>
</figure>
<span>{newArticle.title}</span>
</div>
</div>
</Row>
</Link>
))
)}
</Col>
</Row>
</Container>
)}
</Layout>
)
}
const Article = () => {
return (
<Router>
<Content path="/article/:id" />
</Router>
)
}
export default Article
import { screen, waitFor } from "@testing-library/react"
import React from "react"
import { renderWithRouter } from "../utils/test-util"
import Article from "./article"
import { getListArtikelEdukasi, getArtikelEdukasi } from "../api"
import { artikelEdukasiFactory } from "../components/artikel-edukasi.factory"
describe(`Article`, () => {
it(`shows article from backend`, async () => {
getArtikelEdukasi.mockResolvedValueOnce({
data: { id: 1, title: "Tes Title", content: "Konten artikel ini" },
})
getListArtikelEdukasi.mockResolvedValueOnce({
data: { results: [artikelEdukasiFactory()] },
})
renderWithRouter(<Article />, { route: "/article/1" })
expect(await screen.findByText("Tes Title")).toBeInTheDocument()
await waitFor(() =>
expect(screen.queryByText("Loading...")).not.toBeInTheDocument()
)
})
})
import { fireEvent, screen, waitFor } from "@testing-library/react"
import { navigate } from "gatsby"
import React from "react"
import { getListJadwalDonor, postUserChangePassword } from "../api"
import {
getListJadwalDonor,
getListArtikelEdukasi,
postUserChangePassword,
} from "../api"
import { doSuccessfulLogin } from "../hooks/authenticate.helper"
import { render, renderAuthenticated } from "../utils/test-util"
import ChangePasswordPage from "./changepassword"
......@@ -22,6 +26,7 @@ describe("Change Password", () => {
it("can be accessed from change profile modal", async () => {
getListJadwalDonor.mockResolvedValueOnce({ data: [] })
getListArtikelEdukasi.mockResolvedValue({ data: { results: [] } })
render(<Index />)
fireEvent.click(screen.getByText("Masuk"))
await doSuccessfulLogin()
......
.edukasi .column {
margin: 15px 15px 0;
padding: 0;
}
.edukasi .column:last-child {
padding-bottom: 60px;
}
.edukasi .column::after {
content: "";
clear: both;
display: block;
}
.edukasi .column div {
position: relative;
float: left;
width: 300px;
height: 200px;
margin: 0 0 0 25px;
padding: 0;
}
.edukasi .column div:first-child {
margin-left: 0;
}
.edukasi .column div span {
position: absolute;
bottom: -70px;
left: 0;
z-index: -1;
display: block;
width: 300px;
margin: 0;
padding: 0;
color: #444;
font-size: 18px;
text-decoration: none;
text-align: center;
-webkit-transition: 0.3s ease-in-out;
transition: 0.3s ease-in-out;
opacity: 0;
}
.edukasi figure {
width: 300px;
height: 200px;
margin: 0;
padding: 0;
background: #fff;
overflow: hidden;
}
.edukasi figure:hover + span {
bottom: -55px;
opacity: 1;
}
......@@ -10,6 +10,7 @@ import Layout from "../components/layout"
import SEO from "../components/seo"
import Spinner from "../components/spinner"
import StokDonorChart from "../components/stokdonorchart"
import Slider from "../components/carousel"
import "./index.css"
const Card = ({ header, color, children, className, ...other }) => (
......@@ -105,7 +106,7 @@ const IndexPage = () => {
</Card>
</Col>
<Col xs="12" md="6" xl="6">
<h4>TO DO: Pos Edukasi</h4>
<Slider />
</Col>
</Row>
</Layout>
......
......@@ -2,9 +2,11 @@ import { fireEvent, waitFor } from "@testing-library/react"
import moment from "moment"
import React from "react"
import Index from "."
import { getListJadwalDonor } from "../api"
import { getListJadwalDonor, getListArtikelEdukasi } from "../api"
import { render } from "../utils/test-util"
import { jadwalDonorFactory } from "./jadwal-donor.factory"
getListJadwalDonor.mockResolvedValue({ data: [] })
getListArtikelEdukasi.mockResolvedValue({ data: { results: [] } })
describe(`Index`, () => {
it(`Show jadwal donor for today`, async () => {
......
.card-title {
color: var(--red);
font-weight: bold;
}
.card-text.article {
width: 80%;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 10%;
text-align: justify;
line-height: normal;
}
.card-footer {
background-color: var(--cream);
}
a {
color: var(--red);
}
a:hover {
color: var(--dark-red);
}
\ No newline at end of file
import { Link } from "gatsby"
import React, { useState } from "react"
import { Card, CardDeck } from "react-bootstrap"
import { useQuery } from "react-query"
import { getListArtikelEdukasi } from "../api"
import ErrorRetry from "../components/error-retry"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Spinner from "../components/spinner"
import "../styles/theme.css"
import { paginationArray } from "../utils/array"
import "./kumpulan-artikel.css"
const renderArtikelCard = article => {
return (
<Card key={article.id}>
<Card.Img variant="top" src={article.featured_image} />
<Card.Body>
<Card.Title>
<Link to={"/article/" + article.id}>{article.title}</Link>
</Card.Title>
<Card.Text className="article">
{article.content
.split(". ")
.slice(0, 3)
.join(". ") + ". ..."}
</Card.Text>
</Card.Body>
<Card.Footer>
<Link to={"/article/" + article.id}>Selengkapnya</Link>
</Card.Footer>
</Card>
)
}
const KumpulanArtikel = () => {
const [page, setPage] = useState(1)
const { status, data, refetch } = useQuery(["artikel-edukasi", page], () =>
getListArtikelEdukasi(page)
)
const articles = status === "success" ? data.data.results : []
const firstRowArticles = articles.slice(0, 3)
const secondRowArticles = articles.slice(3, 6)