replyke-rn
Version:
Replyke React Native components: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
277 lines • 15.4 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = GiphyContainer;
var jsx_runtime_1 = require("react/jsx-runtime");
var react_1 = require("react");
var react_native_gesture_handler_1 = require("react-native-gesture-handler");
var react_native_1 = require("react-native");
var icons_1 = require("../icons");
var MAX_ITEMS = 60; // Define the maximum number of items to load
var FETCH_LIMIT = 30;
function GiphyContainer(_a) {
var _this = this;
var onClickBack = _a.onClickBack, onSelectGif = _a.onSelectGif, giphyApiKey = _a.giphyApiKey, visible = _a.visible;
var _b = (0, react_1.useState)([]), gifs = _b[0], setGifs = _b[1];
var _c = (0, react_1.useState)(false), loading = _c[0], setLoading = _c[1];
var _d = (0, react_1.useState)(false), loadingMore = _d[0], setLoadingMore = _d[1];
var _e = (0, react_1.useState)(0), currentOffset = _e[0], setCurrentOffset = _e[1];
var _f = (0, react_1.useState)(0), totalCount = _f[0], setTotalCount = _f[1];
var _g = (0, react_1.useState)(0), flatListWidth = _g[0], setFlatListWidth = _g[1]; // Track the width of the FlatList
// Search states & debouncing
var _h = (0, react_1.useState)(""), query = _h[0], setQuery = _h[1];
var _j = (0, react_1.useState)(""), debouncedQuery = _j[0], setDebouncedQuery = _j[1];
// Refs to track fetching state and gifs length
var isFetchingRef = (0, react_1.useRef)(false);
var gifsLengthRef = (0, react_1.useRef)(0);
// Debounce effect (like in the web version)
(0, react_1.useEffect)(function () {
var handler = setTimeout(function () {
setDebouncedQuery(query);
}, 500); // 500ms debounce
return function () { return clearTimeout(handler); };
}, [query]);
// Update gifsLengthRef when gifs change
(0, react_1.useEffect)(function () {
gifsLengthRef.current = gifs.length;
}, [gifs]);
// Fetch function that decides between trending or search
var fetchGifs = (0, react_1.useCallback)(function () {
var args_1 = [];
for (var _i = 0; _i < arguments.length; _i++) {
args_1[_i] = arguments[_i];
}
return __awaiter(_this, __spreadArray([], args_1, true), void 0, function (offset) {
var url, trimmed, res, json, remainingItems, fetchedItems_1, err_1;
if (offset === void 0) { offset = 0; }
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// Prevent multiple fetches
if (isFetchingRef.current) {
return [2 /*return*/];
}
// Check if we've reached the maximum limit
if (Math.max(gifsLengthRef.current, offset) >= MAX_ITEMS) {
return [2 /*return*/];
}
isFetchingRef.current = true;
if (offset === 0) {
setLoading(true);
setLoadingMore(false);
}
else {
setLoadingMore(true);
}
url = "";
trimmed = debouncedQuery.trim();
if (trimmed.length === 0) {
// Fetch trending if no query
url = "https://api.giphy.com/v1/gifs/trending?api_key=".concat(giphyApiKey, "&limit=").concat(FETCH_LIMIT, "&offset=").concat(offset);
}
else {
// Fetch search results
url = "https://api.giphy.com/v1/gifs/search?api_key=".concat(giphyApiKey, "&q=").concat(encodeURIComponent(trimmed), "&limit=").concat(FETCH_LIMIT, "&offset=").concat(offset);
}
_a.label = 1;
case 1:
_a.trys.push([1, 4, 5, 6]);
return [4 /*yield*/, fetch(url)];
case 2:
res = _a.sent();
return [4 /*yield*/, res.json()];
case 3:
json = (_a.sent());
if (json.meta.status !== 200) {
console.error("API Error:", json.meta.msg);
return [2 /*return*/];
}
setTotalCount(json.pagination.total_count);
setCurrentOffset(json.pagination.offset + json.pagination.count);
remainingItems = MAX_ITEMS - gifsLengthRef.current;
fetchedItems_1 = json.data.slice(0, remainingItems);
if (offset === 0) {
setGifs(fetchedItems_1);
}
else {
setGifs(function (prevGifs) { return __spreadArray(__spreadArray([], prevGifs, true), fetchedItems_1, true); });
}
return [3 /*break*/, 6];
case 4:
err_1 = _a.sent();
console.error("Fetch Error:", err_1);
return [3 /*break*/, 6];
case 5:
if (offset === 0) {
setLoading(false);
}
else {
setLoadingMore(false);
}
isFetchingRef.current = false;
return [7 /*endfinally*/];
case 6: return [2 /*return*/];
}
});
});
}, [debouncedQuery, giphyApiKey]);
// Fetch more GIFs when reaching the end
var fetchMoreGifs = (0, react_1.useCallback)(function () {
if (loading ||
loadingMore ||
gifsLengthRef.current >= totalCount ||
gifsLengthRef.current >= MAX_ITEMS ||
isFetchingRef.current) {
return;
}
fetchGifs(currentOffset);
}, [loading, loadingMore, totalCount, currentOffset, fetchGifs]);
// Reset search and pagination when visibility or query changes
(0, react_1.useEffect)(function () {
if (!visible) {
// Reset all states when not visible
setQuery("");
setDebouncedQuery("");
setGifs([]);
setCurrentOffset(0);
setTotalCount(0);
setLoading(false);
setLoadingMore(false);
isFetchingRef.current = false;
}
else {
// When visibility changes to true, reset offset and fetch initial gifs
setCurrentOffset(0);
setTotalCount(0);
setGifs([]);
fetchGifs(0);
}
}, [visible, debouncedQuery, fetchGifs]);
// Handle ScrollView layout to dynamically calculate column width
var handleLayout = function (event) {
var width = event.nativeEvent.layout.width;
setFlatListWidth(width);
};
var renderMasonryColumns = function () {
if (!flatListWidth)
return null;
var padding = 16; // Total horizontal padding
var columnSpacing = 8; // Spacing between columns
var columnWidth = (flatListWidth - padding - columnSpacing) / 2; // Two columns
// Split data into two columns
var columns = [[], []];
gifs.forEach(function (gif, index) {
columns[index % 2].push(gif); // Alternately add to each column
});
return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: {
flexDirection: "row",
justifyContent: "space-between",
paddingHorizontal: 4,
}, children: columns.map(function (column, colIndex) { return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: { flex: 1, marginHorizontal: 4 }, children: column.map(function (item) {
var aspectRatio = parseInt(item.images.fixed_width.height) /
parseInt(item.images.fixed_width.width);
return ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: { marginBottom: 8 }, onPress: function () {
return onSelectGif({
id: item.id,
url: item.url,
aspectRatio: aspectRatio,
gifUrl: item.images.fixed_width.webp,
gifPreviewUrl: item.images.preview_gif.webp,
altText: item.title,
});
}, children: (0, jsx_runtime_1.jsx)(react_native_1.Image, { source: { uri: item.images.fixed_width.webp }, style: {
width: columnWidth, // Set fixed width
height: columnWidth * aspectRatio, // Calculate height using aspect ratio
borderRadius: 4,
}, resizeMode: "cover" // Equivalent to contentFit="cover"
}) }, item.id));
}) }, colIndex)); }) }));
};
return ((0, jsx_runtime_1.jsxs)(react_native_1.Animated.View, { style: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "white",
zIndex: 999,
opacity: visible ? 1 : 0,
pointerEvents: visible ? "auto" : "none",
}, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
flexDirection: "row",
padding: 8,
alignItems: "stretch",
gap: 8,
}, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: {
backgroundColor: "#e5e7eb",
aspectRatio: 1, // Ensures width equals height
alignItems: "center",
justifyContent: "center",
borderRadius: 8, // Keeps it rounded
}, onPress: onClickBack, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { color: "#888", fontSize: 22, lineHeight: 22 }, children: "\u2190" }) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
flex: 1,
flexDirection: "row",
backgroundColor: "#e5e7eb",
borderRadius: 8,
paddingHorizontal: 16,
alignItems: "center",
gap: 12,
}, children: [(0, jsx_runtime_1.jsx)(icons_1.MagnifyingGlassIcon, { width: 16, color: "#888" }), (0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: {
flex: 1,
paddingVertical: 12,
fontSize: 15,
}, placeholder: "Search GIPHY", onChangeText: function (value) { return setQuery(value); }, value: query })] })] }), loading && gifs.length === 0 ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { textAlign: "center", marginTop: 16 }, children: "Loading..." })) : ((0, jsx_runtime_1.jsxs)(react_native_gesture_handler_1.ScrollView, { onLayout: handleLayout, onScroll: function (_a) {
var nativeEvent = _a.nativeEvent;
var layoutMeasurement = nativeEvent.layoutMeasurement, contentOffset = nativeEvent.contentOffset, contentSize = nativeEvent.contentSize;
var currentScroll = contentOffset.y + layoutMeasurement.height;
var threshold = contentSize.height * 0.8; // 80% scroll
if (currentScroll >= threshold) {
fetchMoreGifs();
}
}, scrollEventThrottle: 16, children: [renderMasonryColumns(), loadingMore && ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { textAlign: "center", marginVertical: 16 }, children: "Loading more..." }))] }))] }));
}
//# sourceMappingURL=GiphyContainer.js.map