File size: 3,276 Bytes
5372a29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { defaultData, type GitHubData } from '../types';

const address = window.location.origin;
const API_URL = address.replace("3000", "4000") + "/api/data";

// Fungsi untuk decode Base64 yang aman untuk Unicode
function b64DecodeUnicode(str: string) {
  try {
    return decodeURIComponent(atob(str).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
  } catch (e) {
    console.error("Gagal mendekode Base64:", e);
    // Kembalikan struktur data default jika gagal
    return JSON.stringify({ questions: [], message: null });
  }
}

// Fungsi untuk encode ke Base64 yang aman untuk Unicode
function b64EncodeUnicode(str: string) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
        function toSolidBytes(match, p1) {
            return String.fromCharCode(parseInt(p1, 16));
    }));
}

export const getData = async (): Promise<{ data: GitHubData, sha: string | null }> => {
  const response = await fetch(API_URL);

  if (response.status === 404) {
    // File tidak ada, ini adalah kondisi yang valid untuk repositori baru.
    return { data: defaultData, sha: null };
  }

  if (!response.ok) {
    const errorData = await response.json().catch(() => ({ message: response.statusText }));
    throw new Error(`Gagal mengambil data dari GitHub: ${errorData.message}`);
  }

  const responseData = await response.json();
  const decodedContent = b64DecodeUnicode(responseData.content || "e30=");
  
  try {
    const data = JSON.parse(decodedContent);
    // Pastikan data memiliki struktur yang diharapkan
    const validatedData: GitHubData = {
      idx: data.idx,
      direction: data.direction
    };
    return { data: validatedData, sha: responseData.sha };
  } catch(e) {
    console.error("Gagal mem-parsing JSON dari GitHub:", e);
    throw new Error("Format data dari GitHub tidak valid.");
  }
};

export const saveData = async (
  data: GitHubData, 
  commitMessage: string, 
  sha: string | null
): Promise<{ sha: string }> => {
  const content = JSON.stringify(data, null, 2);
  const encodedContent = b64EncodeUnicode(content);

  console.dir(data, { depth: null, colors: true });

  const body: { message: string; content: string; sha?: string } = {
    message: commitMessage,
    content: encodedContent,
  };
  
  if (sha) {
    body.sha = sha;
  }

  let isSuccess = false;
  let responseData;

  while (!isSuccess) {
    try {
      const response = await fetch(API_URL, {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(body),
      });


      if (!response.ok) {
        const errorData = await response.json().catch(() => ({ message: response.statusText }));
        throw new Error(`Gagal menyimpan data ke GitHub: ${errorData.message}`);
      }

      responseData = await response.json();
      isSuccess = true;
    } catch (e) {
      if (e.message.includes("does not match")) {
        const newData = await getData();
        body.sha = newData.sha;
      } else {
        isSuccess = true;
      }
    }
  }

  return { sha: responseData.content.sha };
};