Blog Engine with Fresh: Building Post Page
Tags: javascript, webdev, react, fresh
Published: 2022-08-09 07:50:00

{% embed https://dev.to/sokhavuth/table-of-contents-41pd %}
GitHub: [https://github.com/Sokhavuth/deno-fresh](https://github.com/Sokhavuth/deno-fresh)
Deno Deploy: [https://khmerweb-fresh.deno.dev/login](https://khmerweb-fresh.deno.dev/login)
<br/>

```jsx
// routes/admin/post.tsx

/** @jsx h */
import { h } from "preact";
import { setting, secret_key, redis_db } from 'setting';
import { Handlers, PageProps } from "$fresh/server.ts";
import Post from "../../components/admin/post.tsx";
import { verify } from "jwt";
import { getCookies, deleteCookie } from "cookies";


export const handler: Handlers = {
    async GET(req, ctx) {
        const cookies = getCookies(req.headers);
        const jwt = await redis_db.get(cookies.session_id);
        if((cookies)&&(cookies.session_id)){
            try{
                const payload = await verify(jwt, secret_key, "HS512");
                if(payload.user){
                    const config = setting()
                    config.page_title = "ទំព័រ​ការផ្សាយ"
                    config.user_name = payload.user.title

                    return await ctx.render({"setting": config})
                }
            }catch(error){
                console.log(error)
                const resp = new Response(undefined, { headers: {location: `/login`}, status: 302 })
                deleteCookie(resp.headers, "session_id")
                return resp
            }
        }

        return new Response(undefined, { headers: {location: `/login`}, status: 302 })
    },
}

export default function Template(props: PageProps){
    return (
        <Post data={props.data} />
    )
  }
```

```jsx
// components/admin/post.tsx

/** @jsx h */
import { h } from "preact";
import { PageProps } from "$fresh/server.ts";
import Index from "./index.tsx";


function PostTsx(props: PageProps){
    const item = props.data.setting.item
    let editor = ``
    let videos = ``

    if(item){
        editor = `
            <form action="/admin/post/edit/${item.id}" name="form" method="post" 
            onSubmit="submitForm(event)">
              <input type="text" name="title" value="${item.title}" required 
              placeholder="ចំណង​ជើង" />
              <textarea id="editor" name="content" >${item.content}</textarea>
              <input type="text" name="categories" value="${item.categories.toString()}" required 
              placeholder="បណ្តា​ជំពូក" />
              <div class="wrapper"> 
                  <select id="category" onChange="getCategory()">
                    <option>ជ្រើសរើស​ជំពូក</option>
                    <option>News</option>
                    <option>Movie</option>
                    <option>Entertainment</option>
                    <option>Sport</option>
                  </select>
                  <input type="text" name="thumb" value="${item.thumb}" required 
                  placeholder="តំណរ​ភ្ជាប់​រូប​តំណាង" />
                  <input type="datetime-local" value="${item.date}" name="datetime" required />
                  <input type="submit" value="បញ្ជូន" />
                  <input type="hidden" name="videos" value='${item.videos}' />
              </div>
            </form>
        `
        videos = `
        let is_video = null
        is_video = JSON.parse('${item.videos}')
    
        if((is_video !== '') && (is_video !== '[]')){
          let html = ''
          let episode = is_video.length
        
          for(let video of is_video){
              html += "<div>"
              html += '<input value="'+video.type+'" required />'
              html += '<input value="'+video.id+'" required />'
              html += '<input value="'+video.status+'" required />'
              html += '<p title="Delete" onClick="deleteRow(event)" class="episode">'+(episode--)+'</p>'
              html += "</div>"
          }
    
          if($('.viddata div').html() === ''){
            $('.viddata div').append('<b>ប្រភេទ​</b>')
            $('.viddata div').append('<b>អត្តសញ្ញាណ​</b>')
            $('.viddata div').append('<b>ស្ថានភាព</b>')
            $('.viddata div').append('<b>ភាគ/លុប</b>')
          }
        
          $('.viddata div:eq(0)' ).after(html)
        }
        `
    }else{
        editor = `
            <form action="/admin" name="form" method="post" onSubmit="submitForm(event)">
              <input type="text" name="title" required placeholder="ចំណង​ជើង" />
              <textarea id="editor" name="content"></textarea>
              <input type="text" name="categories" required placeholder="បណ្តា​ជំពូក" />
              <div class="wrapper"> 
                  <select id="category" onChange="getCategory()">
                    <option>ជ្រើសរើស​ជំពូក</option>
                    <option>News</option>
                    <option>Movie</option>
                    <option>Entertainment</option>
                    <option>Sport</option>
                  </select>
                  <input type="text" name="thumb" required placeholder="តំណរ​ភ្ជាប់​រូប​តំណាង" />
                  <input type="datetime-local" name="datetime" required />
                  <input type="submit" value="បញ្ជូន" />
                  <input type="hidden" name="videos" value="" />
              </div>
            </form>
        `
        videos = ``
    }

    return(
        <section class="Post">
            <script src="/scripts/ckeditor/ckeditor.js"></script>
            <script src="/scripts/getCategory.js"></script>
            <script src="/scripts/video.js"></script>
            <link rel="stylesheet" href="/styles/admin/post.css" />

            <div dangerouslySetInnerHTML={{__html: `
                ${editor}
            `}}/>
            
            <script src="/scripts/ckeditor/config.js"></script>

            <div class="wrapper" >
                <select name="type">
                  <option>YouTube</option>
                  <option>YouTubePL</option>
                  <option>Facebook</option>
                  <option>OK</option>
                </select>
                <input type="text" name="videoid" required placeholder="អត្តសញ្ញាណ​វីដេអូ" />
                <select name="status">
                  <option>ចប់</option>
                  <option>នៅ​មាន​ត</option>
                  <option>~ ចប់</option>
                </select>
                <div dangerouslySetInnerHTML={{__html: `
                    <input onclick="genJson()" type="submit" value="បញ្ចូល​វីដេអូ" />
                `}} />
            </div>

            <div class='viddata'>
              <div></div>
            </div>
            <script dangerouslySetInnerHTML={{__html: `${videos}`}}/>
        </section>
    )
}


export default function Post(props: PageProps){
    props.data.page_inner = PostTsx;
    return(
        <Index data={props.data} />
    )
}
```

```jsx
// components/admin/index.tsx

/** @jsx h */
import { h } from "preact";
import { PageProps } from "$fresh/server.ts";
import Base from "../base.tsx"


function IndexTsx(props: PageProps){
    const Page = props.data.page_inner;
    return(
        <section class="Index" >
        <link rel="stylesheet" href="/styles/admin/index.css" />
        <header>
          <div class="inner region">
              <div class="title">{props.data.setting.page_title}</div>
              <form action="/admin/search" method="post">
                <select name="admin_search">
                  <option>ការផ្សាយ</option>
                  <option>សៀវភៅ</option>
                </select>
                <input type="text" name="admin_q" required placeholder="Search" />
                <input type="submit" value="ស្វែងរក" />
              </form>
              <div class="logout"><span>{props.data.setting.user_name}</span> | <a href="/">ទំព័រ​មុខ</a> | <a href="/logout">ចេញ​ក្រៅ</a></div>
          </div>
        </header>

        <div class="main region">
          <div class="sidebar">
            <div class="inner">
              <a href="/admin"><img src="/images/movie.png" /></a>
              <a href="/admin">ការផ្សាយ</a>

              <a href="/admin/book"><img src="/images/books.png" /></a>
              <a href="/admin/book">សៀវភៅ</a>

              <a href="/admin/category"><img src="/images/category.png" /></a>
              <a href="/admin/category">ជំពូក</a>

              <a href="/admin/upload"><img src="/images/upload.png" /></a>
              <a href="/admin/upload">Upload</a>

              <a href="/admin/user"><img src="/images/users.png" /></a>
              <a href="/admin/user">អ្នក​ប្រើប្រាស់</a>

              <a href="/admin/setting"><img src="/images/setting.png" /></a>
              <a href="/admin/setting">Setting</a>
            </div>
          </div>
          <div class="content">
            <Page data={props.data} />
          </div>
        </div>

        <div class="footer region">
          <div class="info">សរុប​ទាំងអស់​មាន​ចំនួនៈ {props.data.setting.count}</div>
          <ul class="list">
              
          </ul>
          <div class="pagination"><img src="/images/load-more.png" /></div>
          <div class="credit">&copy; <a href="https://khmerweb.vercel.app/">Khmer Web 2022</a></div>
        </div>
      </section>
    )
}


export default function Index(props: PageProps){
    props.data.page = IndexTsx;
    return(
        <Base data={props.data} />
    )
}
```

```jsx
// components/base.tsx

/** @jsx h */
import { h } from "preact";
import { PageProps } from "$fresh/server.ts";


export default function Base(props: PageProps){
    const Page = props.data.page;
    return(
        <html>
          <head>
            <meta charSet="UTF-8"/>
            <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
            <title>{props.data.setting.site_title} | {props.data.setting.page_title}</title>
            <link href="/styles/base.css" rel="stylesheet" />
            <link href="/fonts/setup.css" rel="stylesheet" />
            <script src="/scripts/jquery.js"></script>
          </head>
          <body>
            <Page data={props.data} />
          </body>
        </html>
    )
  }
```