반응형

오늘 갑작스레 메일이 와서 내용을 보니, AI NAVER API 가 7월1일자로 전면 유료화가 된다고 한다.

처음에 네이버 지도 API 를 ncloud 에서 신청해서 쓰고 있었는데, 그게 AI NAVER API 로 들어가 있었고, 또 Maps API가 별도로 카테고리가 생성되어 있었다. 그러니까 요약하자면, AI NAVER API 내에 있는 Maps 를 쓰면 7월1일부터 무조건 과금이 되고, 그 밖에 있는 Maps 를 쓰면 기존처럼 무료로 이용이 가능하다.

 

하지만 나처럼 AI NAVER API 내에 Maps를 쓰고 있던 사용자라면은 기존 사이트에 있던 Client ID, Secret를 Maps에 새로 생성한 Application에 맞게 전부 수정해주고, api 주소들 역시 전부 Maps 에 맞게 변경해주어야 한다.

 

Javascript CDN 주소는 아래 링크를 참고해 수정하시고,

https://navermaps.github.io/maps.js.ncp/docs/tutorial-2-Getting-Started.html

 

NAVER Maps API v3

NAVER Maps API v3로 여러분의 지도를 만들어 보세요. 유용한 기술문서와 다양한 예제 코드를 제공합니다.

navermaps.github.io

 

API 각 요청 경로는 아래 문서를 참고해 수정하자.

https://api.ncloud-docs.com/docs/application-maps-overview

 

Maps 개요

 

api.ncloud-docs.com

 

변경해 준다음에 AI NAVER API 내에 있는 Application 은 삭제를 해주었다.

 

반응형
반응형

Failed to set fetch cache https://xx.com/xx.jpg Error: fetch for over 2MB of data can not be cached

 

오류가 발생했을 때, 아래와 같이 조치하면 된다.

# 1
fecth('xx', { cache: 'no-store' });

# 2
export const dynamic = 'force-dynamic';

 

반응형
반응형

next-auth 를 설치하고 나서 인증 성공시 리디렉션 되는 경로의 포트가 3000이 기본으로 되어있어 실제 사용중인 포트가 일치하지 않는 문제가 생겼다. 검색하다보니 아래 URL에서 .env 에서 설정을 가이드하고 있어 변경하고 정상동작함을 확인했다.

 

https://next-auth.js.org/configuration/options#nextauth_url

 

Options | NextAuth.js

Environment Variables

next-auth.js.org

 

NEXTAUTH_URL="http://localhost:5000"

 

이런식으로 .env 파일에 NEXTAUTH_URL 을 설정해주면, redirect 시에 포트가 정상적으로 내가 원하는 값으로 변경이 되었다 

반응형
반응형

kakao sdk.js 는 로드되었을지 몰라도 latlng method 가 로드되기 전에 호출될 경우 발생하는 문제이다.

다음과 같이 수정하여 해결하였다.

 

sdk.js 호출시 파라미터에 autoload=false 를 추가해주었다.

<script
  async
  src={`https://dapi.kakao.com/v2/maps/sdk.js?appkey=${KAKAO_JAVASCRIPT_APP_KEY}&autoload=false`}
></script>

 

그다음 latlng 메소드가 호출되는 부분을 kakao.maps.load callback 처리해주었다.

 

useEffect(() => {
    if (kakao) {
      kakao.maps.load(() => {
        var container = document.getElementById('map'); //지도를 담을 영역의 DOM 레퍼런스
        var options = {
          //지도를 생성할 때 필요한 기본 옵션
          center: new kakao.maps.LatLng(Number(lat), Number(lng)), //지도의 중심좌표.
          level: 3, //지도의 레벨(확대, 축소 정도)
        };

        var map = new kakao.maps.Map(container as HTMLDivElement, options);
        var markerPosition = new kakao.maps.LatLng(Number(lat), Number(lng));

        // 마커를 생성합니다
        var marker = new kakao.maps.Marker({
          position: markerPosition,
        });

        // 마커가 지도 위에 표시되도록 설정합니다
        marker.setMap(map);
      });
    }
  }, [lat, lng]);
반응형
반응형

오늘은 요구사항으로 새 윈도우 창에 post 로 보내달라는 게 있어서 포스팅에 추가해봅니다.

Vanilla로 짜도되고 jQuery를 쓰셔도 되는데, 두가지를 모두 소개해볼게요.

 

Vanilla

var form = document.createElement('form');
form.setAttribute('target', '_blank');
form.setAttribute('action', '__TARGET_URL__');
form.setAttribute('method', 'post');

var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('value', '__VALUE__HERE__');
input.setAttribute('name', '__NAME__HERE__');

form.append(input);
document.body.appendChild(form);
form.submit();

 

jQuery

var form = $("<form \>");
form.attr({
    "target": "_blank",
    "action": "__URL__HERE__",
    "method": "post"
});

form.append($("<input \>").attr({
    "type": "hidden",
    "value": "__VALUE__HERE__",
    "name": "__NAME__HERE__"
}))

$("body").append(form);
form.submit();
반응형
반응형
const isJson = (str: string) => {
  try {
    const json = JSON.parse(str);
    return json && typeof json === 'object';
  } catch (e) {
    return false;
  }
};
반응형
반응형

Copy & Paste 시에 텍스트만 가져오도록 처리 onpaste 이벤트에 걸면된다.

const getTextByPasteClipboard = (e) => {
  e.preventDefault();
  let text;
  const clp = (e.originalEvent || e).clipboardData;
  if (clp === undefined || clp === null) {
    // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
    // @ts-ignore
    text = window.clipboardData.getData('text') || '';
    if (text !== '') {
      text = text.replace(/<[^>]*>/g, '');
      if (window.getSelection) {
        const newNode = document.createElement('span');
        newNode.innerHTML = text;
        window.getSelection().getRangeAt(0).insertNode(newNode);
      } else {
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        document.selection.createRange().pasteHTML(text);
      }
    }
  } else {
    text = clp.getData('text/plain') || '';
    if (text) {
      text = text.replace(/<[^>]*>/g, '');
      document.execCommand('insertText', false, text);
    }
  }
};
반응형
반응형
const getImageSize = (file: File, callback: (width: number, height: number) => void) => {
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = (e) => {
    const image = new Image();
    image.src = e.target.result as string;
    image.onload = function () {
      // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
      // @ts-ignore
      callback(this.width, this.height);
    };
  };
}

 

반응형

+ Recent posts